【问题标题】:LocalStorage not updating property in state with React hooksLocalStorage 未使用 React 钩子更新状态中的属性
【发布时间】:2020-05-02 23:03:34
【问题描述】:

我正在尝试更新之前在 useState 挂钩中为表单值声明的对象属性,并将其保存在本地存储中。一切顺利,但是localstorage一直将日期属性保存为空,我知道这一定是因为异步但我找不到解决方案。这是我的代码。我是 React 钩子的新手。非常感谢!

  const [formValues,setformValues] = useState(
    {
      userName:'',
      tweetText:'',
      date:''
    }
  )

  const getlocalValue = () => {
    const localValue = JSON.parse(localStorage.getItem('tweetList'));
    if(localValue !== null){
      return localValue
    } else {
      return []
    }
  }

  const [tweetList,setTweetList] = useState(getlocalValue());

  const handleInput = (inputName,inputValue) => {
    setformValues((prevFormValues) => {
      return {
        ...prevFormValues,
        [inputName]:inputValue
      }
    })
  }

  const handleForm = () => {
    const {userName,tweetText} = formValues;
    if(!userName || !tweetText) {
      console.log('your tweet is empty');
    } else {
      setformValues(prevFormValues => {
        return {
          ...prevFormValues,
          date:getCurrentDate() //this is not updating in local
        }
      })
      setTweetList(prevTweets => ([...prevTweets, formValues]));
      toggleHidden(!isOpen)
    }

  }
  console.log(formValues) //but you can see changes outside the function


  useEffect(() => {
    localStorage.setItem('tweetList', JSON.stringify(tweetList));
  }, [tweetList]);

【问题讨论】:

    标签: reactjs react-hooks use-effect


    【解决方案1】:

    在这种情况下,问题是因为被调用的 handleForm 在它被调用时仍然只能访问 formValues 状态,而不是新状态。因此,处理这个问题的最简单方法是只更新 formValues、setFormValues,然后根据更新后的 formValues 的本地副本 setTweetList。

      const handleForm = () => {
        const {userName,tweetText} = formValues;
        if(!userName || !tweetText) {
          console.log('your tweet is empty');
        } else {
          const updatedFormValues = {...formValues,date:getCurrentDate()};
          setformValues(updatedFormValues)
          setTweetList(prevTweets => ([...prevTweets, updatedFormValues]));
          toggleHidden(!isOpen)
        }
      }
    

    由于这里存在并发问题:即您不能保证使用最新数据更新 formValues 和 tweetList 的状态。另一种选择是 useReducer 而不是两个单独的状态变量,因为它们是相关的属性,您可以更轻松地基于彼此更新它们。

    作为使用 reducer 进行更复杂更新的示例,我添加了一个“FINALIZE_TWEET”操作,它将同时执行操作的两个部分。

    const Component = () => {
      const [{ formValues, tweetList }, dispatch] = useReducer(
        reducer,
        undefined,
        getInitState
      );
    
      const handleInput = (inputName, inputValue) => {
        dispatch({ type: 'SET_FORM_VALUE', payload: { inputName, inputValue } });
      };
    
      const handleForm = () => {
        const { userName, tweetText } = formValues;
        if (!userName || !tweetText) {
          console.log('your tweet is empty');
        } else {
          dispatch({ type: 'SET_FORM_DATE' });
          dispatch({ type: 'PUSH_TO_LIST' });
          // OR
          // dispatch({type: 'FINALIZE_TWEET'})
          toggleHidden(!isOpen);
        }
      };
      console.log(formValues); //but you can see changes outside the function
    
      useEffect(() => {
        localStorage.setItem('tweetList', JSON.stringify(tweetList));
      }, [tweetList]);
    
      return <div></div>;
    };
    
    const getlocalValue = () => {
      const localValue = JSON.parse(localStorage.getItem('tweetList'));
      if (localValue !== null) {
        return localValue;
      } else {
        return [];
      }
    };
    function getInitState() {
      const initialState = {
        formValues: {
          userName: '',
          tweetText: '',
          date: '',
        },
        tweetList: getlocalValue(),
      };
    }
    
    function reducer(state, action) {
      switch (action.type) {
        case 'SET_FORM_VALUE':
          return {
            ...state,
            formValues: {
              ...state.formValues,
              [action.payload.inputName]: action.payload.inputValue,
            },
          };
        case 'SET_FORM_DATE':
          return {
            ...state,
            formValues: {
              ...state.formValues,
              date: getCurrentDate(),
            },
          };
        case 'PUSH_TO_LIST':
          return {
            ...state,
            tweetList: [...state.tweetList, state.formValues],
          };
        case 'FINALIZE_TWEET': {
          const newTweet = {
            ...state.formValues,
            date: getCurrentDate(),
          };
          return {
            ...state,
            formValues: newTweet,
            tweetList: [...state.tweetList, newTweet],
          };
        }
        default:
          return state;
      }
    }
    

    【讨论】:

    • 感谢您的回答!它现在正在工作,我将采用你的第一种方法,因为我现在正试图理解钩子和减速器,我发现第一个解决方案更容易理解:) 但我记住你的第二个答案:)
    猜你喜欢
    • 2021-03-22
    • 2019-10-29
    • 1970-01-01
    • 2019-04-01
    相关资源
    最近更新 更多