反应 UserContext:useEffect 中的条件被忽略 [英] React UserContext: Conditional in useEffect is being ignored

查看:74
本文介绍了反应 UserContext:useEffect 中的条件被忽略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 useContext 钩子来制作共享状态的组件到其他组件.

现在这个组件也将状态保存到本地存储.

var initialState = {头像:'/static/uploads/profile-avatars/placeholder.jpg',isRoutingVisible: 假,removeRoutingMachine:假,标记:[],当前地图:{}};var UserContext = React.createContext();函数 setLocalStorage(key, value) {函数 isJson(item) {item = typeof item !== 'string' ?JSON.stringify(item) : item;尝试 {item = JSON.parse(item);}赶上(e){返回假;}if (typeof item === 'object' && item !== null) {返回真;}返回假;}尝试 {window.localStorage.setItem(key, JSON.stringify(value));} 捕捉(错误){//捕捉可能的错误:控制台日志(错误);}}函数 getLocalStorage(key, initialValue) {尝试 {const value = window.localStorage.getItem(key);返回值?JSON.parse(value) : 初始值;}赶上(e){返回初始值;}}功能用户提供者({孩子}){const [user, setUser] = useState(() => getLocalStorage('user', initialState));

在我声明一些 useEffect 钩子之后:

const [isLengthOfUserMarkersLessThanTwo,setIsLengthOfUserMarkersLessThanTwo] = useState(true);useEffect(() => {setLocalStorage('用户', 用户);}, [用户]);useEffect(() => {console.log('user.isRoutingVisibile', user.isRoutingVisibile);}, [user.isRoutingVisibile]);useEffect(() => {console.log('user.markers.length', user.markers.length);if (user.markers.length === 2) {setIsLengthOfUserMarkersLessThanTwo(false);}返回 () =>{};}, [JSON.stringify(user.markers)]);

最后一个钩子是头刮板,我在依赖项中传递一个数组,当数组长度达到 2 时,我想做出反应(哈!)做一些事情.

当它到达那里时,我有一个 useState 钩子,它会改变一个变量的值.

 const [isLengthOfUserMarkersLessThanTwo,setIsLengthOfUserMarkersLessThanTwo] = useState(true);

我有一个函数,我想将它传递给另一个组件,该函数只能在三元返回 true 时触发.

现在尽管数组的长度变为 2,setIsLengthOfUserMarkersLessThanTwo 并没有将变量更改为 false

返回 (<UserContext.Provider价值={{setUserMarkers: 标记 =>{console.log('标记', 标记);控制台.日志('isLengthOfUserMarkersLessThanTwo ',isLengthOfUserMarkersLessThanTwo);isLengthOfUserMarkersLessThanTwo === true?设置用户(用户 =>({...用户,标记:[...user.markers, 标记]})): () =>空值;},}}>{孩子们}</UserContext.Provider>);

先谢谢你!

解决方案

将函数作为状态传递可能不是你想要的,还传递函数来更新反应状态的切片,被一个伟大的舞台经理简单地解决了作为还原.对于简单的项目,redux 可能有点矫枉过正,react 本身可以通过 Context 在幕后处理这些场景.使用 react Hooks 也将变得更具可读性.这里有一个简单的演示,展示了如何使用 React 钩子使其更具可预测性.

const UserStateContext = React.createContext()const UserDispatchContext = React.createContext()函数 userReducer(state, {type, payload}){开关(类型){案例'setId':{返回 {...状态,id:payload.id}}案例'setAvatar':{返回 {...状态,头像:payload.avatar}}//...默认: {throw new Error(`未处理的操作类型:${type}`)}}}常量初始状态 = {头像:'/static/uploads/profile-avatars/placeholder.jpg',isRoutingVisible: 假,//...};函数 UserProvider({children}) {const [state, dispatch] = React.useReducer(userReducer, initialState)返回 (<UserStateContext.Provider value={state}><UserDispatchContext.Provider value={dispatch}>{孩子们}</UserDispatchContext.Provider></UserStateContext.Provider>)}函数 useUserState() {返回 React.useContext(UserStateContext)}函数 useUserDispatch() {返回 React.useContext(CountDispatchContext)}函数使用用户(){返回 [useUserState(), useUserDispatch()]}

现在您可以在子组件中使用它,如下所示:

const AvatarChildren = () =>{const [用户,调度] = useUser()返回 (<div><img src={user.avatar}/><按钮onClick={() =>dispatch({ type: 'setAvatar',有效载荷:{头像:'newAvatarSrc'} })}>更改头像

)}

你甚至可以让它更简单,比如

const userReducer = (state, action) =>({状态,...动作})

并像这样使用它

onClick={() =>调度({头像:'newAvatarSrc'})}

I am using the useContext hook to make a component which shares state to other components.

Right now this component is saving the state to local storage as well.

var initialState = {
  avatar: '/static/uploads/profile-avatars/placeholder.jpg',
  isRoutingVisible: false,
  removeRoutingMachine: false,
  markers: [],
  currentMap: {}
};

var UserContext = React.createContext();

function setLocalStorage(key, value) {
  function isJson(item) {
    item = typeof item !== 'string' ? JSON.stringify(item) : item;

    try {
      item = JSON.parse(item);
    } catch (e) {
      return false;
    }

    if (typeof item === 'object' && item !== null) {
      return true;
    }

    return false;
  }

  try {
    window.localStorage.setItem(key, JSON.stringify(value));
  } catch (errors) {
    // catch possible errors:
    console.log(errors);
  }
}

function getLocalStorage(key, initialValue) {
  try {
    const value = window.localStorage.getItem(key);
    return value ? JSON.parse(value) : initialValue;
  } catch (e) {
    return initialValue;
  }
}

function UserProvider({ children }) {
  const [user, setUser] = useState(() => getLocalStorage('user', initialState));

Right after I am declaring some useEffect hooks:

const [
    isLengthOfUserMarkersLessThanTwo,
    setIsLengthOfUserMarkersLessThanTwo
  ] = useState(true);

  useEffect(() => {
    setLocalStorage('user', user);
  }, [user]);

  useEffect(() => {
    console.log('user.isRoutingVisibile ', user.isRoutingVisibile);
  }, [user.isRoutingVisibile]);

  useEffect(() => {
    console.log('user.markers.length ', user.markers.length);
    if (user.markers.length === 2) {
      setIsLengthOfUserMarkersLessThanTwo(false);
    }

    return () => {};
  }, [JSON.stringify(user.markers)]

);

The last hook is the head scratcher, I am passing an array in the dependency, which I'd like to react (ha!) to do something when the array length gets to two.

When it does get there, I have a useState hook which will change the value of a variable.

 const [
    isLengthOfUserMarkersLessThanTwo,
    setIsLengthOfUserMarkersLessThanTwo
  ] = useState(true);

I have a function which I'd like to pass to another component which should only be able to fire when the ternary return true.

Right now despite the Array's length getting to two, the setIsLengthOfUserMarkersLessThanTwo doesn't change the variable to false

return (
    <UserContext.Provider
      value={{
     
        setUserMarkers: marker => {
          console.log('marker ', marker);

          console.log(
            'isLengthOfUserMarkersLessThanTwo ',
            isLengthOfUserMarkersLessThanTwo
          );
          isLengthOfUserMarkersLessThanTwo === true
            ? setUser(user => ({
                ...user,
                markers: [...user.markers, marker]
              }))
            : () => null;
        },
        
      }}
    >
      {children}
    </UserContext.Provider>
  );

Thank you in advance!

解决方案

Passing function as a state may not be what you want, also passing the function to update a slice of reacting state, is simply solved by a great stage manager such as redux. for simple projects, redux may be overkill, react itself can handle these scenarios by Context behind the scene. It will also become more readable with react Hooks. here is a simple demonstration of how to use React hooks to make it more predictable.

const UserStateContext = React.createContext()
const UserDispatchContext = React.createContext()

function userReducer(state, {type, payload}){
  switch (type) {
    case 'setId': {
      return {...state, id: payload.id}
    }
    case 'setAvatar': {
      return {...state, avatar: payload.avatar}
    }
    // ...
    default: {
      throw new Error(`Unhandled action type: ${type}`)
    }
  }
}

const initialState = {
  avatar: '/static/uploads/profile-avatars/placeholder.jpg',
  isRoutingVisible: false,
  // ...
};


function UserProvider({children}) {
  const [state, dispatch] = React.useReducer(userReducer, initialState)
  return (
    <UserStateContext.Provider value={state}>
      <UserDispatchContext.Provider value={dispatch}>
        {children}
      </UserDispatchContext.Provider>
    </UserStateContext.Provider>
  )
}

function useUserState() {
  return React.useContext(UserStateContext)
}

function useUserDispatch() {
  return React.useContext(CountDispatchContext)
}

function useUser() {
  return [useUserState(), useUserDispatch()]
}

Now you can use this in children component like the following:

const AvatarChildren = () => {
  const [user, dispatch] = useUser()

  return (
    <div>
      <img src={user.avatar} />
      <button 
        onClick={() => dispatch({ type: 'setAvatar', 
                                  payload: {avatar: 'newAvatarSrc'} })}
      >
       Change Avatar
      </button>
    </div>
  )
}

You can even make it simpler such as

const userReducer = (state, action) => ({state, ...action})

and use it like this

onClick={() => dispatch({avatar: 'newAvatarSrc'})}

这篇关于反应 UserContext:useEffect 中的条件被忽略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆