使用useEffect钩子获取后,ReactJS上下文重新呈现

时间:2019-11-20 09:48:17

标签: javascript reactjs

我目前正在尝试通过整个应用程序与context provider传递数据,但是触发的挂钩仅返回其初始值,并且不重新触发

这是我的App主组件中的应用程序布局,该组件没有任何状态。

class App extends Component {
  render() {
    return (
      <div>
        <BrowserRouter>
          <UserContextProvider>
            <div className="container">
              <Header />
              <Switch>
                <Route exact path="/" component={Home} />
                <Route exact path="/login" component={LoginPage} />
                <PrivateRoute exact path="/secret-page" component={SecretPage} />
              </Switch>
            </div>
          </UserContextProvider>
        </BrowserRouter>
      </div>
    );
  }
}

export default App;

无论何时App组件首次渲染时,它都会触发UserContextProvider,后者触发onEffect钩子。该挂钩尝试获取数据,但是由于用户尚未登录,因此它仅返回其原始值[]

这里是上下文提供者

const UserContextProvider = ({children}) => {
  const [userSettings, setUserSettings] = useState([]);
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  useEffect(() => {
    if (userid !== null) {
      fetch(
        process.env.REACT_APP_API_URL + "/authenticated/get-permissions",
        requestOptions
      )
        .then(response => response.json())
        .then(response => {
          setUserSettings(response.data);
          setIsLoggedIn(true);
        })
        .catch(error => console.log(error));
    } else {
      console.log(userSettings);
      setIsLoggedIn(false);
    }
  }, []);
  return (
    <UserContext.Provider value={userSettings}>{children}</UserContext.Provider>
  );
};

现在,当上面的代码最初触发时,userid的值为null,但是在LoginPage子组件中进行身份验证之后,它将变为令牌。我的问题是,即使userid的值在登录后发生更改,该钩子也不会再次触发。

我只想提到我从一个单独的文件中的本地存储中获取userid值并将其导入。

我尝试在函数内部的空数组参数中设置userid值,但这不起作用。

useEffect值更改后,如何使我的userid钩再次触发?

---编辑-----

userid是通过以下方式从名为fetchRequestOptions的另一个文件中导入的:

import {requestOptions, userid} from "./fetchRequestOptions";

在我的fetchRequestOptions文件中,我有以下代码:

let userid = localStorage.getItem("userid");
let accessToken = localStorage.getItem("accesstoken");
let requestOptions ={ <my request options are here>}

3 个答案:

答案 0 :(得分:1)

为了使使用userid的挂钩在更改时可以重新运行,您需要将其保持在一个状态内。然后,LoginPage需要连接到上下文并使用setUserid来更新其值。

const UserContextProvider = ({ children }) => {
    const [userSettings, setUserSettings] = useState([]);
    const [isLoggedIn, setIsLoggedIn] = useState(false);
    // If you are reading directly from localstorage you might
    // want to use localStorage.getItem("userid") as the initial value
    const [userid, setUserid] = useState(null);

    useEffect(() => {
        // ...
    }, [userid]);

    return (
        <UserContext.Provider value={{ userSettings, setUserid }}>
            {children}
        </UserContext.Provider>
    );
};

关键是userid必须处于状态内,这样它就可以在需要其最新值的任何Component中触发新的渲染。

您可能会发现Context内有一个特定的自定义钩子可以处理用户ID的逻辑(获取和更新),这更清洁。这是一个不错的选择,但只能使userid在此上下文中可用。如果您需要在其他地方使用它,则需要从上下文value属性中导出它。

const useUserid = () => {
    const [userid, setUserid] = useState(null);

    useEffect(() => {
        const fetched_userid = //...
        setUserid(fetched_userid);
    }, []);

    return userid;
};

const UserContextProvider = ({ children }) => {
    // ...
    const userid = useUserid();

    useEffect(() => {
        // ...
    }, [userid]);

    return (
        <UserContext.Provider value={userSettings}>{children}</UserContext.Provider>
    );
};

答案 1 :(得分:0)

在useEffect挂钩中传递空数组[]意味着(根据React文档)

  

如果要运行效果并仅将其清理一次(在挂载和卸载时),则可以将空数组([])作为第二个参数传递。这告诉React,您的效果不依赖于道具或状态的任何值,因此它不需要重新运行

因此,我们需要传递可触发效果以重新渲染的道具/状态。

答案 2 :(得分:0)

在useEffect的依赖项数组中传递userid作为参数。这样可以确保只要userid发生更改,效果就可以运行。

  useEffect(() => {
   ...
  }, [userid]);