React之表單


 

第一部分:表單基礎

在React中,修改表單的唯一途徑是使用setState方法。舉例如下:

  

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

ReactDOM.render(
  <NameForm />,
  document.getElementById('root')
);

 

 

  在codepen的運行代碼連接

  

  我們可以看出其運行邏輯:首先將組建渲染到頁面,及執行了render(),此時獲取的value為空,當我們輸入數據時,觸發handleChange函數(注意:要提前綁定在當前環境下),然后設置state中的value為用戶當前輸入值,於是表單元素input獲取到最新的state並使用虛擬dom與真實dom作對比,只更新有變化的dom...  當點擊提交按鈕時,觸發了handleSubmit函數。

  值得注意的是:在handleSubmit函數中,我們使用event.preventDefault()阻止了默認行為,即:提交表單后,不會自動reset表單,而是保留之前的用戶數據!

 

第二部分:textarea表單

  textarea表單和Input表單本身是沒有什么區別的,舉例如下所示:

class EssayForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 'Please write an essay about your favorite DOM element.'
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('An essay was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <textarea value={this.state.value} onChange={this.handleChange} style={{color:'red',width:'400px',height:'15px'}} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

ReactDOM.render(
<EssayForm/>,
document.getElementById('root')
);

   這里我設置了初始狀態,所以一開始我們就可以在textarea中看到內容,稍有不同的是,我還在textarea中設置了樣式(注意:要用兩個curly brace,外面的表示包含js對象,里面的表示包含一個樣式對象,當然我們也可以在外面先定義對象然后再傳進來)。

  另外,我們還可以直接在css中設置樣式,如下所示:

textarea{
  background:red;
  color:white !important;
}

  這樣,背景顏色為紅色,字體為白色。

  注意:因為在React中設置的style是行內樣式,優先級較高,故在外聯樣式中無法覆蓋,只有通過使用!important的方式才能成功覆蓋。

 

  另外,將樣式對象傳入的方法如下:

render() {
    var myStyle = {
        width:'400px',
        height:'15px',
        color:'red'
                  }; 
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <textarea value={this.state.value} onChange={this.handleChange} style={myStyle} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );

 

 

 

 

第三部分:select表單

  例子如下所示:

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite La Croix flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

ReactDOM.render(
  <FlavorForm />,
  document.getElementById('root')
);

 

連接。

 

 

第四部分:復雜表單

   舉例如下所示:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

ReactDOM.render(
  <Reservation />,
  document.getElementById('root')
);

連接

 

 

第五部分:lifting state up

  舉例如下:

const scaleNames = {
  c: 'Celsius',
  f: 'Fahrenheit'
};

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {value: '545445'};
  }

  handleChange(e) {
    this.setState({value: e.target.value});
  }

  render() {
    const value = this.state.value;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={value}
               onChange={this.handleChange} />
      </fieldset>
    );
  }
}

class Calculator extends React.Component {
  render() {
    return (
      <div>
        <TemperatureInput scale="c" />
        <TemperatureInput scale="f" />
      </div>
    );
  }
}

ReactDOM.render(
  <Calculator />,
  document.getElementById('root')
);

 鏈接。

 

 

兩個input聯動

const scaleNames = {
  c: 'Celsius',
  f: 'Fahrenheit'
};

function toCelsius(fahrenheit) {
  return (fahrenheit - 32) * 5 / 9;
}

function toFahrenheit(celsius) {
  return (celsius * 9 / 5) + 32;
}

function tryConvert(value, convert) {
  const input = parseFloat(value);
  if (Number.isNaN(input)) {
    return '';
  }
  const output = convert(input);
  const rounded = Math.round(output * 1000) / 1000;
  return rounded.toString();
}

function BoilingVerdict(props) {
  if (props.celsius >= 100) {
    return <p>The water would boil.</p>;
  }
  return <p>The water would not boil.</p>;
}

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.props.onChange(e.target.value);
  }

  render() {
    const value = this.props.value;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={value}
               onChange={this.handleChange} />
      </fieldset>
    );
  }
}

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = {value: '', scale: 'c'};
  }

  handleCelsiusChange(value) {
    this.setState({scale: 'c',value});
  }

  handleFahrenheitChange(value) {
    this.setState({scale: 'f',value});
  }

  render() {
    const scale = this.state.scale;
    const value = this.state.value;
    const celsius = scale === 'f' ? tryConvert(value, toCelsius) : value;
    const fahrenheit = scale === 'c' ? tryConvert(value, toFahrenheit) : value;

    return (
      <div>
        <TemperatureInput
          scale="c"
          value={celsius}
          onChange={this.handleCelsiusChange} />
        <TemperatureInput
          scale="f"
          value={fahrenheit}
          onChange={this.handleFahrenheitChange} />
        <BoilingVerdict
          celsius={parseFloat(celsius)} />
      </div>
    );
  }
}

ReactDOM.render(
  <Calculator />,
  document.getElementById('root')
);

 

鏈接

  

 值得注意的是: 如果幾個組件都需要訪問(獲取)相同的state, 那么這是一個我們需要將state提升(listing)到他們幾個共同的相同的祖先組件中的信號!在我們的例子中,就是Calculator。 我們存儲了value 和 scale 在Calculator的state中。

 兩個input將會保持同步,因為他們基於相同的state。

 不管你在哪個input中輸入,this.state.value和this.state.scale都會更新。

 即通常,如果一個組件需要state來render,這時我們可以將之添加到這個組件中,但是如果另外一個組件也需要這個state,我們就可以把這個state提升到兩者最近的祖先中去。相反於嘗試着去同步兩個不同組件的state,我們應當依賴於top-down data flow,即React中獨特的自上而下的數據流。

 

 

 

  入門react不得不看的例子。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM