【问题标题】:Input text - 'defaultValue' is not loading the state value and 'value' is not updated on change输入文本 - “defaultValue”未加载状态值,“value”未在更改时更新
【发布时间】:2020-08-24 21:13:03
【问题描述】:

我有一个输入文本如下(MovieInput.tsx):

<input 
    id="inputMovieTitle" 
    type="text"
    onChange={ e => titleHandleChange(e) }
    value={ getTitle() }>
</input>

titleHandleChange:

const [title, setTitle] = useState('');

const titleHandleChange = (e: ChangeEvent<HTMLInputElement>) => {        
    setTitle(e.target.value);
}

获取标题:

const moviesInState = useSelector((state: any) => state.movies);

const getTitle = () => {      
    console.log(moviesInState.item.title); // It displays correct movie title from the store corresponding to the selected row
    return moviesInState.item.title;
}

我有一个表格 (Grid.tsx),其中列出了该州 (state.movi​​es.items[]) 中的所有电影。当我单击该表中的任何电影行时,所选电影将在商店中更新,即 state.movi​​es.item。

Grid.tsx:

const dispatch = useDispatch();

const selectMovie = (movie: Movie) => {
    const movieSelected: Movie = {
        _id: movie._id,
        __v: movie.__v,
        title: movie.title,
        rating: movie.rating,
        year: movie.year
    }
    dispatch(getMovie(movieSelected));
}
...
<tbody>
    {
        props.allMovies.map((movie: Movie) => 
            <tr onClick={() => selectMovie(movie)}>
                <td>{movie.title}</td>
                <td>{(+movie.rating).toFixed(1)}</td>
                <td>{movie.year}</td>
            </tr>
        )
    }
</tbody>

现在,当我单击表 (Grid.tsx) 中的任何行时,它会更新 store 中的 store.movi​​es.item,并且文本输入(在 MovieInput.tsx 中)显示所选电影的标题。当我更改所选行时,文本输入的值也会更新。

为什么要在文本输入中加载所选电影的标题文本?

因为,我应该能够编辑标题值并更新数据库中的记录。我选择任何行,更改其标题,然后单击“更新”按钮并保存。但是,尽管文本已成功填充到文本输入中并且在我们更改所选行时正确更改,但文本输入仍然“不可编辑”。这是由于以下代码:

value={ getTitle() }>

当我将 'value' 更改为 'defaultValue' 时,我可以编辑文本输入,但是这一次,当我选择另一行时,文本值没有改变。

defaultValue={ getTitle() }>

它工作正常并显示更新的值(当我更改选定的行时),直到我编辑输入。首次编辑后,它不会在另一行单击时更改其值。仅保留已编辑的文本,但我希望在选择另一行时该值会发生变化。但是,getTitle() 函数内的控制台日志会显示与所选行相对应的商店 (store.movi​​es.item) 中的正确标题。

请告诉我如何执行以下操作?

  • 使文本输入可编辑
  • 在更改所选行后使文本输入更改其值(即使在输入被编辑之前它应该丢失编辑并更改为新值)

【问题讨论】:

    标签: javascript reactjs typescript react-redux react-hooks


    【解决方案1】:

    更改后输入不显示更新值的原因是因为它通过moviesInState绑定到您的redux存储中的值。

    据我所知,您希望输入的初始值来自 getTitle(),而输入的更新值应该来自用户输入的任何内容。

    因此,您应该更改的第一件事是使用存储中的值设置title 状态的初始值。

    const moviesInState = useSelector((state: any) => state.movies);
    const getTitle = () => {      
        console.log(moviesInState.item.title); // It displays correct movie title from the store corresponding to the selected row
        return moviesInState.item.title;
    }
    const [title, setTitle] = useState(getTitle());
    

    鉴于必须在更新存储时更新输入,因此需要 useEffect 挂钩来传播状态中的更新。

    useEffect(() => {
      if (moviesInState.item.title !== title) {
        setTitle(moviesInState.item.title);
      }
    }, [moviesInState]);
    

    接下来,将title 状态绑定到inputvalue 属性。 titleHandleChange 方法没有问题,因此我们可以保持原样。另外,不需要依赖defaultValue,所以我们可以去掉它的使用。

    <input 
      id="inputMovieTitle" 
      type="text"
      onChange={titleHandleChange}
      value={title}>
    </input>
    

    另一方面,您不应该使用any,因为这将消除 TypeScript 类型检查功能的好处。相反,您应该将 state 参数定义为您为 redux 存储定义的根状态类型。例如,

    const moviesInState = useSelector((state: RootState) => state.movies);
    

    【讨论】:

    • 谢谢。我试过这个。但是,标题输入值既不加载也不改变。但它是可编辑的。
    • @MAK 嗯.. 你的意思是它没有加载初始值?尝试这样做吗? const [title, setTitle] = useState(moviesInState.item.title);
    • 如果还是不行,试着在useState语句之前运行console.log(moviesInState.item.title);,告诉我它打印了什么?
    • 我按你说的试过了。 const [title, setTitle] = useState(moviesInState.item.title);它没有加载值。
    • console.log(moviesInState.item.title); 打印了以下内容:第一次选择 Movie1 --> 打印了两次 Movie1。第二个选择 Movie3 --> 打印两次 Movie1 和两次 Movie3。第三次选择 --> Movie7 --> 打印两次 Movie3 和两次 Movie7。
    猜你喜欢
    • 2016-07-10
    • 2015-07-20
    • 1970-01-01
    • 2021-06-17
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 2020-01-28
    相关资源
    最近更新 更多