在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問(wèn)答/Linux  HTML/ react的value和defaultValue之間的困惑

react的value和defaultValue之間的困惑

跟著網(wǎng)上各種教程入門(mén)react,決定做一個(gè)todolist來(lái)加深對(duì)react的理解
因?yàn)橹皩W(xué)過(guò)一陣子vue,用vue做的todolist直接把最終的效果圖拿來(lái)重新用react做
圖片描述

上圖就是用vue做的
說(shuō)一下這個(gè)todo具備的功能:
1.輸入框輸入后直接按回車(chē)或者點(diǎn)擊新增按鈕時(shí),將文本添加到下面展示列表部分。
2.每項(xiàng)前的checkbox勾選后文本部分標(biāo)記已完成并且不能編輯
3.每項(xiàng)鼠標(biāo)劃過(guò)在最右端出現(xiàn)刪除的'x'點(diǎn)擊可以刪除該項(xiàng)
4.文本部分用的input[type='text'],點(diǎn)擊文本可以修改文本。當(dāng)發(fā)生失焦事件或者回車(chē)按下事件時(shí),判斷與之前的文本是否一致,不一致彈出確認(rèn)框,確認(rèn)框點(diǎn)擊確認(rèn)進(jìn)行修改,點(diǎn)擊取消還原成之前的文本內(nèi)容。

問(wèn)題出現(xiàn)在,用react做的時(shí)候,input[type='text']的屬性用value必須得配合onChange,但是這一塊我不會(huì)做,
如果用defaultValue出現(xiàn)一個(gè)情況就是,不點(diǎn)擊刪除確認(rèn)的話(huà),顯示沒(méi)問(wèn)題,但是點(diǎn)擊刪除一項(xiàng)時(shí),defaultValue不會(huì)再次渲染,所以刪除后的列表顯示的文本內(nèi)容還是刪除之前的內(nèi)容。
希望哪位大神耐心看一下我的代碼,幫我一下~

我也希望有對(duì)我代碼優(yōu)化改進(jìn)之類(lèi)的建議

貼一下改動(dòng)后的代碼:

import React, { Component } from 'react';

import './App.less';


//去除兩邊空格
function trim(str){
  return str.replace(/(^\s*)|(\s*$)/g, "");
}

//新增事項(xiàng)組件
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="請(qǐng)輸入添加事項(xiàng)" onKeyDown={this.addhandler} ref={input => this.input=input} />
        </div>
      </div>
    )
  }
}
//顯示代辦事項(xiàng)組件
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>您的待辦事項(xiàng)</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> 個(gè)事項(xiàng), 其中 完成事項(xiàng): <span className="color02">{finished}</span> 個(gè), 代辦事項(xiàng): <span className="color03">{nofinished}</span> 個(gè).
      </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>
    );
  }
}

//創(chuàng)建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事件
現(xiàn)在可以達(dá)到我想要的功能效果了

雖然功能實(shí)現(xiàn)了,但是我覺(jué)得我的代碼看著很混亂,有些代碼感覺(jué)很冗余但是又不知道該如何優(yōu)化提煉,比如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':''}/>

這部分,我添加了好多事件,這一塊是否可以去掉不必要的代碼,或者這些事件所調(diào)用的方法是否可以整合去寫(xiě),再有 每個(gè)事件我想傳遞當(dāng)前對(duì)象作為參數(shù),而我寫(xiě)的是.bind(null,index)傳遞的是該對(duì)象在數(shù)組的索引值

回答
編輯回答
舊城人

既然用defaultValue,表明你這個(gè)組件是個(gè)非受控組件,無(wú)法人為控制value。而defaultValue只能作用一次

解決方案就是把它變成受控組件,至于你說(shuō)的不會(huì)用onChange,這個(gè)可以搜一下,不難

2017年12月17日 17:31