【Web前端问题】react的value和defaultValue之间的困惑

跟着网上各种教程入门react,决定做一个todolist来加深对react的理解
因为之前学过一阵子vue,用vue做的todolist直接把最终的效果图拿来重新用react做
图片描述

上图就是用vue做的
说一下这个todo具备的功能:
1.输入框输入后直接按回车或者点击新增按钮时,将文本添加到下面展示列表部分。
2.每项前的checkbox勾选后文本部分标记已完成并且不能编辑
3.每项鼠标划过在最右端出现删除的'x'点击可以删除该项
4.文本部分用的input[type='text'],点击文本可以修改文本。当发生失焦事件或者回车按下事件时,判断与之前的文本是否一致,不一致弹出确认框,确认框点击确认进行修改,点击取消还原成之前的文本内容。

问题出现在,用react做的时候,input[type='text']的属性用value必须得配合onChange,但是这一块我不会做,
如果用defaultValue出现一个情况就是,不点击删除确认的话,显示没问题,但是点击删除一项时,defaultValue不会再次渲染,所以删除后的列表显示的文本内容还是删除之前的内容。
希望哪位大神耐心看一下我的代码,帮我一下~

我也希望有对我代码优化改进之类的建议

贴一下改动后的代码:

import React, { Component } from 'react';

import './App.less';

//去除两边空格

function trim(str){

return str.replace(/(^\s*)|(\s*$)/g, "");

}

//新增事项组件

class AddPanel extends Component {

constructor(props){

super(props);

this.addhandler = this.addhandler.bind(this);

/*this.ButtonAddHandler = this.ButtonAddHandler.bind(this);*/

}

addhandler(e){

var ListDataArr = this.props.ListDataArr;

var inputStr = this.input.value;

var trimStr = trim(inputStr);

if(( e.target.type === 'text' && e.keyCode === 13 ) || e.target.type === 'button'){

if(trimStr){

ListDataArr.push({

text:trimStr,

ischecked: false

});

this.props.SetInputToListData(ListDataArr);

}

this.input.value = '';

}

}

render(){

return (

<div className="addpanel clearfix">

<button type="button" onClick={this.addhandler}>新增</button>

<div className="addinput">

<input type="text" placeholder="请输入添加事项" onKeyDown={this.addhandler} ref={input => this.input=input} />

</div>

</div>

)

}

}

//显示代办事项组件

class ListPanel extends Component {

constructor(props){

super(props);

this.state = {

inputText: ''

};

this.changeChecked = this.changeChecked.bind(this);

this.modification = this.modification.bind(this);

this.keydownModification = this.keydownModification.bind(this);

this.deletehandler = this.deletehandler.bind(this);

this.textrecord = this.textrecord.bind(this);

this.bindinputvalue = this.bindinputvalue.bind(this);

}

changeChecked(index){

var ListDataArr = this.props.ListDataArr;

ListDataArr[index].ischecked = !ListDataArr[index].ischecked;

this.props.checkhandler(ListDataArr);

}

modification(index,e){

var ListDataArr = this.props.ListDataArr;

var afterStr = trim(e.target.value);

if(afterStr === this.state.inputText){

ListDataArr[index].text = afterStr;

this.props.checkhandler(ListDataArr);

}else{

var conf = window.confirm('确定修改么?');

if(conf){

ListDataArr[index].text = afterStr;

this.props.checkhandler(ListDataArr);

}else{

ListDataArr[index].text = this.state.inputText;

this.props.checkhandler(ListDataArr);

}

}

}

keydownModification(index,e){

if(e.keyCode === 13){

this.modification(index,e);

}

}

deletehandler(index,e){

var ListDataArr = this.props.ListDataArr;

var conf = window.confirm('确定删除么?');

if(conf){

ListDataArr.splice(index,1);

this.props.checkhandler(ListDataArr);

}

}

textrecord(index,e){

this.setState({

inputText: e.target.value

})

console.log(e.target.value);

}

bindinputvalue(index,e){

var ListDataArr = this.props.ListDataArr;

ListDataArr[index].text = e.target.value;

this.props.checkhandler(ListDataArr);

}

render(){

var ListDataArr = this.props.ListDataArr;

return (

<div className="listpanel">

<h3>您的待办事项</h3>

<ul>

{

ListDataArr.map((item,index) => {

return (

<li key={index+1}>

<span>

<input type="checkbox" onChange={this.changeChecked.bind(null,index)} checked={item.ischecked?true:false}/>

{index+1+": "}

</span>

<div>

<input type="text" value={item.text} onChange={this.bindinputvalue.bind(null,index)} onFocus={this.textrecord.bind(null,index)} onBlur={this.modification.bind(this,index)} onKeyDown={this.keydownModification.bind(null,index)} disabled={item.ischecked?true:false} className={item.ischecked?'done':''}/>

</div>

<i onClick={this.deletehandler.bind(null,index)}></i>

</li>

)

})

}

</ul>

</div>

);

}

}

class Statistics extends Component {

render(){

var ListDataArr = this.props.ListDataArr,

total = ListDataArr.length,

finished = 0,

nofinished = 0;

ListDataArr.forEach(function(item,index){

if(item.ischecked){

finished++;

}else{

nofinished++;

}

})

return (

<div className="statisticsPanel">

共: <span className="color01">{total}</span> 个事项, 其中 完成事项: <span className="color02">{finished}</span> 个, 代办事项: <span className="color03">{nofinished}</span> 个.

</div>

);

}

}

class App extends Component {

constructor(props){

super(props);

this.state = {

ListDataArr: storage.fetch(),

}

this.SetInputToListData = this.SetInputToListData.bind(this);

}

SetInputToListData(arr){

arr.map((item,index) =>{

return (item.id = index);

});

this.setState({

ListDataArr: arr

});

storage.save(arr);

}

render() {

console.log(JSON.stringify(this.state.ListDataArr));

return (

<div id="app">

<AddPanel ListDataArr={this.state.ListDataArr} SetInputToListData={this.SetInputToListData}></AddPanel>

<ListPanel ListDataArr={this.state.ListDataArr} checkhandler={this.SetInputToListData}></ListPanel>

<Statistics ListDataArr={this.state.ListDataArr}></Statistics>

</div>

);

}

}

//创建localstorage

var storageName = 'todolist-react';

const storage = {

fetch(){

return JSON.parse(localStorage.getItem(storageName) || '[]');

},

save(jsondata){

localStorage.setItem(storageName,JSON.stringify(jsondata));

}

}

export default App;

按照一楼给的解决思路,把defaultValue换成了value 并添加onChange事件
现在可以达到我想要的功能效果了

虽然功能实现了,但是我觉得我的代码看着很混乱,有些代码感觉很冗余但是又不知道该如何优化提炼,比如ListPanel组件里的

<input type="text" value={item.text} onChange={this.bindinputvalue.bind(null,index)} onFocus={this.textrecord.bind(null,index)} onBlur={this.modification.bind(this,index)} onKeyDown={this.keydownModification.bind(null,index)} disabled={item.ischecked?true:false} className={item.ischecked?'done':''}/>

这部分,我添加了好多事件,这一块是否可以去掉不必要的代码,或者这些事件所调用的方法是否可以整合去写,再有 每个事件我想传递当前对象作为参数,而我写的是.bind(null,index)传递的是该对象在数组的索引值

回答:

既然用defaultValue,表明你这个组件是个非受控组件,无法人为控制value。而defaultValue只能作用一次

解决方案就是把它变成受控组件,至于你说的不会用onChange,这个可以搜一下,不难

以上是 【Web前端问题】react的value和defaultValue之间的困惑 的全部内容, 来源链接: utcz.com/a/140334.html

回到顶部