TL;DR 使用Context
说明:
每个组件都有它的自定义钩子实例。
在下面的示例中,我们可以看到调用setState 会更改Bla 组件中的状态,但不会更改Foo 组件中的状态:
const { Fragment, useState, useEffect } = React;
const useCustomHook = () => {
const [state, setState] = useState('old');
return [state, setState];
};
const Foo = () => {
const [state] = useCustomHook();
return <div>state in Foo component: {state}</div>;
};
const Bla = () => {
const [state, setState] = useCustomHook();
return (
<div>
<div>state in Bla component: {state}</div>
<button onClick={() => setState("new")}>setState</button>
</div>
);
};
function App() {
return (
<Fragment>
<Foo />
<Bla />
</Fragment>
);
}
ReactDOM.render(<App />, document.querySelector('#root'));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>
Context 和自定义钩子的组合可以用来解决上述问题:
const { createContext, useContext, useState, useEffect } = React;
const Context = createContext();
const ContextProvider = ({ children }) => {
const value = useState("old");
return <Context.Provider value={value} children={children} />;
};
const useCustomHook = () => {
const [state, setState] = useContext(Context);
return [state, setState];
};
const Foo = () => {
const [state] = useCustomHook();
return <div>state in Foo component: {state}</div>;
};
const Bla = () => {
const [state, setState] = useCustomHook();
return (
<div>
<div>state in Bla component: {state}</div>
<button onClick={() => setState("new")}>setState</button>
</div>
);
};
function App() {
return (
<ContextProvider>
<Foo />
<Bla />
</ContextProvider>
);
}
ReactDOM.render(<App />, document.querySelector('#root'));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>
针对 OP 想要的原始答案:
定义上下文:
import React from 'react';
const PlayersContext = React.createContext();
const PlayersProvider = PlayersContext.Provider;
export const usePlayersContext = () => React.useContext(PlayersContext);
export default function PlayersProvider({ children }) {
// add all the logic, side effects here and pass them to value
const { list, loading, error } = useSelector(
(state) => state.accounts.players
);
const dispatch = useDispatch();
useEffect(() => {
try {
const response = authAxios.get(endpoints.players.retrieve);
response.then((res) => {
dispatch({
type: 'SET_PLAYERS_LIST',
payload: {
error: false,
loading: false,
list: res.data.payload,
},
});
});
} catch (e) {
console.log(e);
dispatch({
type: 'SET_PLAYERS_LIST',
payload: {
error: true,
loading: false,
list: [],
},
});
}
}, [dispatch]);
return <PlayersProvider value={{ list, loading, error }}>{children}</PlayersProvider>;
}
将PlayersProvider 作为父组件添加到需要访问播放器的组件中。
在那些子组件内部:
import {usePlayersContext} from 'contextfilepath'
function Child() {
const { list, loading, error } = usePlayersContext()
return ( ... )
}
您还可以在 Provider 本身而不是在 redux 中维护状态。