React学习总结-v16.4.0(菜鸟)

112 阅读12分钟

React-v16.4.0

组件

组件创建及引用

函数定义

// 子组件
import React from 'react'
function HelloWorld(props) {
  return <h1>Hello World!</h1>;
}
export default HelloWorld

// 父组件
import HelloWorld from './views/components/helloworld.js'

function App() {
  return (
    <div className="App">
      <HelloWorld />
    </div>
  )
}

export default App

Class 定义

// 子组件
import React from 'react'
class HelloWorld extends React.Component {
  render() {
    return <span>Hello World!</span>
  }
}

export default HelloWorld

// 父组件
import HelloWorld from './views/components/helloworld.js'

function App() {
  return (
    <div className="App">
      <HelloWorld />
    </div>
  )
}

export default App

Props

Demo

// 父组件
import HelloWorld from './views/components/helloworld.js'

function App() {
  return (
    <div className="App">
      <HelloWorld name="Runoob" />	// 直接在这里面去传
    </div>
  );
}

export default App;


// 子组件
import React from "react";
class HelloWorld extends React.Component {
  constructor(props) {
    super(props);
    console.log('props', props);  // {name: 'Runoob'}
  }
  getProps() {
    console.log(this.props);  // {name: 'Runoob'}
  }
  render() {
    this.getProps()
    return <span>{this.props.name}</span>;
  }
}

export default HelloWorld;

默认 Props

// 父组件
import Props from './views/components/Props.js'
import './App.css'
function App() {

  return (
    <div className="App">
      <Props/>
    </div>
  );
}

export default App;


// 子组件

import React from "react";

class Props extends React.Component {
  constructor(props) {
    super(props);
    console.log('props', props);  // {name: 'Runoob'}
  }
  getProps() {
    console.log(this.props);  // {name: 'Runoob'}
  }
  render() {
    this.getProps()
    return (
      <div>
        <h2>{this.props.name}</h2>
      </div>
    )
  }
}
Props.defaultProps = {
  name: 'Runoob'	// 设置默认Props,避免父组件不传入。
};
export default Props;

State 和 Props 组合使用

class ShowName extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return <h2>姓名是: {this.props.name}</h2>;
  }
}
function ShowAge(props) {
  return <h2>年龄是: {props.age}</h2>;
}
class Props extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "123",
      age: 456,
    };
  }
  render() {
    return (
      <div>
        <ShowName name={this.state.name} />
        <ShowAge age={this.state.age} />
      </div>
    );
  }
}

export default Props;

Props 验证(就是限制是否必须,数据类型)

import PropTypes from "prop-types"; // 需要安装prop-types依赖,在React v15.5 版本后已经移到了 prop-types 库。

function ShowAge(props) {
  return <h2>年龄是: {props.age}</h2>;
}
/**
 * 这玩意儿和Vue的Props的type是一样的,格式不对的时候会warn
 * react-jsx-dev-runtime.development.js:87 Warning: Failed prop type: Invalid prop `age` of type `string` supplied to `ShowAge`, expected `number`.
 */
ShowAge.propTypes = {
  age: PropTypes.number,
};
class Props extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      age: "456", // 目前格式就是错误的.要num给了str
    };
  }
  render() {
    return (
      <div>
        <ShowAge age={this.state.age} />
      </div>
    );
  }
}

验证器枚举

ShowAge.propTypes = {
  // 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的
  optionalArray: PropTypes.array,
  optionalBool: PropTypes.bool,
  optionalFunc: PropTypes.func,
  optionalNumber: PropTypes.number,
  optionalObject: PropTypes.object,
  optionalString: PropTypes.string,
  optionalNode: PropTypes.node, // 可以被渲染的对象 numbers, strings, elements 或 array
  optionalElement: PropTypes.element, //  React 元素
  optionalMessage: PropTypes.instanceOf(Message), // 用 JS 的 instanceof 操作符声明 prop 为类的实例。
  optionalEnum: PropTypes.oneOf(["News", "Photos"]), // 用 enum 来限制 prop 只接受指定的值。
  // 可以是多个对象类型中的一个
  optionalUnion: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.instanceOf(Message),
  ]),
  optionalArrayOf: PropTypes.arrayOf(PropTypes.number), // 指定类型组成的数组
  optionalObjectOf: PropTypes.objectOf(PropTypes.number), // 指定类型的属性构成的对象
  // 特定 shape 参数的对象
  optionalObjectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number,
  }),
  requiredFunc: PropTypes.func.isRequired, // 任意类型加上 `isRequired` 来使 prop 不可空。
  requiredAny: PropTypes.any.isRequired, // 不可空的任意类型
  // 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
  customProp: function (props, propName, componentName) {
    if (!/matchme/.test(props[propName])) {
      return new Error("Validation failed!");
    }
  },
};

State

Demo

import React from "react";

class State extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date: "",
    };
  }
  componentDidMount() {
    this.timerID = setInterval(() => this.changeState(), 1000);
  }
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
  changeState() {
    this.setState({ date: new Date().toLocaleTimeString() });
  }
  render() {
    return (
      <div>
        <h2>当前时间是: {this.state.date}</h2>
      </div>
    );
  }
}

export default State;

代码执行顺序

  1. <Clock /> 被传递给 ReactDOM.render() 时,React 调用 Clock 组件的构造函数。 由于 Clock 需要显示当前时间,所以使用包含当前时间的对象来初始化 this.state 。 我们稍后会更新此状态。
  2. React 然后调用 Clock 组件的 render() 方法。这是 React 了解屏幕上应该显示什么内容,然后 React 更新 DOM 以匹配 Clock 的渲染输出。
  3. Clock 的输出插入到 DOM 中时,React 调用 componentDidMount() 生命周期钩子。 在其中,Clock 组件要求浏览器设置一个定时器,每秒钟调用一次 tick()
  4. 浏览器每秒钟调用 tick() 方法。 在其中,Clock 组件通过使用包含当前时间的对象调用 setState() 来调度 UI 更新。 通过调用 setState() ,React 知道状态已经改变,并再次调用 render() 方法来确定屏幕上应当显示什么。 这一次,render() 方法中的 this.state.date 将不同,所以渲染输出将包含更新的时间,并相应地更新 DOM。
  5. 一旦 Clock 组件被从 DOM 中移除,React 会调用 componentWillUnmount() 这个钩子函数,定时器也就会被清除。

数据流走向

State 父组件 ---> ShowDateView 子组件

import React from "react";

function ShowDateView(props) {
  return <h2>当前时间是: {props.date}</h2>;
}

class State extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date: "",
    };
  }
  // 生命周期: 在组件挂载后(插入 DOM 树中)立即调用。
  componentDidMount() {
    this.timerID = setInterval(() => this.changeState(), 1000);
  }
  // 生命周期: 在组件卸载及销毁之前直接调用。
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
  changeState() {
    this.setState({ date: new Date().toLocaleTimeString() });
  }
  render() {
    return (
      <div>
        <ShowDateView date={this.state.date} /> // 向子组件流向数据
      </div>
    );
  }
}

export default State;

React 事件处理

React 元素的事件处理和 DOM 元素类似。但是有一点语法上的不同:

  • React 事件绑定属性的命名采用驼峰式写法,而不是小写。
  • 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)

HTML 通常写法是:

<button onclick="activateLasers()">激活按钮</button>

React 中写法为:

<button onClick={activateLasers}>激活按钮</button>

阻止默认行为(e.preventDefault)

在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为, 你必须明确使用 preventDefault。

例如,通常我们在 HTML 中阻止链接默认打开一个新页面,可以这样写:

<a href="#" onclick="console.log('点击链接'); return false"> 点我 </a>

在 React 的写法为:

import React from "react";
class Event extends React.Component {
  constructor(opt) {
    super(opt);
  }

  render() {
    function handleClick(e) {
      e.preventDefault(); // 这样写就可以阻止a标签的跳转行为
      console.log("链接被点击了");
    }
    return (
      <a href="#" target="_blank" onClick={handleClick}>
        点击我
      </a>
    );
  }
}

export default Event;

监视器(绑定 this)

使用 React 的时候通常你不需要使用 addEventListener 为一个已创建的 DOM 元素添加监听器。你仅仅需要在这个元素初始渲染的时候提供一个监听器。

当你使用 ES6 class 语法来定义一个组件的时候,事件处理器会成为类的一个方法。例如,下面的 Toggle 组件渲染一个让用户切换开关状态的按钮:

class Event extends React.Component {
  constructor(opt) {
    super(opt);
    this.state = {
      isToggleOn: true,
    };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState((prevState) => ({
      isToggleOn: !prevState.isToggleOn,
    }));
  }
  render() {
    return (
      <a type="button" onClick={this.handleClick}>
        {this.state.isToggleOn ? "我是开启的状态" : "我是关闭的状态"}
      </a>
    );
  }
}

export default Event;

JSX 回调函数中的 this,类的方法默认是不会绑定this的。如果你忘记绑定 this.handleClick 并把它传入 onClick, 当你调用这个函数的时候 this 的值会是 undefined。

监视器(不用绑定 this)

① 使用箭头函数,箭头函数的 this 指向定义者,而一般函数里的 this 指向其调用者;

class Event extends React.Component {
  constructor(opt) {
    super(opt);
    this.state = {
      isToggleOn: true,
    };
  }
  handleClick = () => {
    this.setState((prevState) => ({
      isToggleOn: !prevState.isToggleOn,
    }));
  };
  render() {
    return (
      <a type="button" onClick={this.handleClick}>
        {this.state.isToggleOn ? "我是开启的状态" : "我是关闭的状态"}
      </a>
    );
  }
}
export default Event;

② 在函数绑定时候处理

class Event extends React.Component {
  constructor(opt) {
    super(opt);
    this.state = {
      isToggleOn: true,
    };
  }
  handleClick() {
    this.setState((prevState) => ({
      isToggleOn: !prevState.isToggleOn,
    }));
  }
  render() {
    return (
      <a type="button" onClick={(e) => this.handleClick(e)}>
        {this.state.isToggleOn ? "我是开启的状态" : "我是关闭的状态"}
      </a>
    );
  }
}
export default Event;

向事件处理程序传递参数

通过箭头函数的方式,事件对象必须显式的进行传递

通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

class Event extends React.Component {
  constructor(opt) {
    super(opt);
    this.state = {
      isToggleOn: true,
      word: "我点击了我自己",
    };
  }
  handleClick(word, e) {
    e.preventDefault();
    alert(word);
  }
  render() {
    return (
      <div>
        <a onClick={(e) => this.handleClick(this.state.word, e)}>箭头函数</a>
        <a onClick={this.handleClick.bind(this, this.state.word)}>bind绑定</a>
      </div>
    );
  }
}

React 条件渲染

React 中的条件渲染和 JavaScript 中的一致,使用 JavaScript 操作符 if 或条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI。

import React from "react";
class TiaoJianXuanRan extends React.Component {
  constructor(props) {
    super(props);
    this.isLogin = props.isLogin;
  }
  render() {
    if (this.isLogin) {
      return <h1>欢迎回来!</h1>;
    } else {
      return <h1>请先登录!</h1>;
    }
  }
}
export default TiaoJianXuanRan;

元素变量

通过变量 isLogin,来判断登录登出按钮展示的切换

function LoginBtn(props) {
  return <div>{props.word}</div>;
}
function LogoutBtn(props) {
  return <div>{props.word}</div>;
}
class TiaoJianXuanRan extends React.Component {
  constructor(props) {
    super(props);
    this.handleLogin = this.handleLogin.bind(this);
    this.handleLogout = this.handleLogout.bind(this);
    this.state = {
      isLogin: true,
    };
  }
  handleLogin(e) {
    this.setState({ isLogin: true });
  }
  handleLogout(e) {
    this.setState({ isLogin: false });
  }
  render() {
    let btn = null;
    const isLogin = this.state.isLogin;
    if (!isLogin) {
      btn = <LoginBtn word={"暂时还没有登录---请先点击登录"} />;
    } else {
      btn = <LogoutBtn word={"您已登录---点击登出"} />;
    }
    return (
      <div>
        <Button type="primary" onClick={this.handleLogin}>
          登录
        </Button>
        <Button type="primary" onClick={this.handleLogout}>
          登出
        </Button>
        {btn}
      </div>
    );
  }
}

与运算符 &&

function MaibBox(props) {
  return <h1>{props.content}</h1>;
}
class TiaoJianXuanRan extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      content: "我是内容",
    };
  }
  render() {
    return (
      <div>
        <h1>下面的内容根据是否有 content来显示</h1>
        {this.state.content && <MaibBox content={this.state.content} />}
      </div>
    );
  }
}
export default TiaoJianXuanRan;

三目运算符

function MaibBox(props) {
  return <h1>{props.content}</h1>;
}
class TiaoJianXuanRan extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      content: "我是内容",
    };
  }
  render() {
    return (
      <div>
        <h1>下面的内容根据是否有 content来显示</h1>
        {this.state.content ? (
          <MaibBox content={this.state.content} />
        ) : (
          <MaibBox content={"没有content, 我是占位字符"} />
        )}
      </div>
    );
  }
}
export default TiaoJianXuanRan;

阻止组件渲染

function WarningBanner(props) {
  if (props.warn) {
    return null;
  }
  return <Alert message="warning Text" type="warning" />;
}
class TiaoJianXuanRan extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      showWarning: true,
    };
    this.handleShowWarning = this.handleShowWarning.bind(this);
  }
  handleShowWarning() {
    this.setState((preState) => ({
      showWarning: !preState.showWarning,
    }));
  }
  render() {
    return (
      <div>
        <Button type="primary" onClick={this.handleShowWarning}>
          {this.state.showWarning ? "隐藏" : "显示"}
        </Button>
        <WarningBanner warn={this.state.showWarning} />
      </div>
    );
  }
}
export default TiaoJianXuanRan;

React 列表 & Keys (v-for key)

import React from "react";
class ListAndKeys extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      numbers: [1, 2, 3, 4, 5],
    };
  }

  render() {
    const listItems = this.state.numbers.map((number) => (
      <li key={number.toString()}>{number}</li>
    ));
    console.log(listItems);
    return <ul>{listItems}</ul>;
  }
}
export default ListAndKeys;

Keys

Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。 当元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key:

import React from "react";
class ListAndKeys extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      numbers: [1, 2, 3, 4, 5],
    };
  }

  render() {
    const listItems = this.state.numbers.map((number, index) => (
      <li key={index}>{number}</li>
    ));
    console.log(listItems);
    return <ul>{listItems}</ul>;
  }
}

用 keys 提取组件

元素的 key 只有在它和它的兄弟节点对比时才有意义。 比方说,如果你提取出一个 ListItem 组件,你应该把 key 保存在数组中的这个 元素上,而不是放在 ListItem 组件中的

  • 元素上。

  • function ListItem(props) {
      return <li>{props.value}</li>;
    }
    class ListAndKeys extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          numbers: [1, 2, 3, 4, 5],
        };
      }
    
      render() {
        const listItems = this.state.numbers.map((number, index) => (
          <ListItem key={index} value={number} />
        ));
        return <ul>{listItems}</ul>;
      }
    }
    export default ListAndKeys;
    

    key 应该唯一

    数组元素中使用的 key 在其兄弟之间应该是独一无二的。然而,它们不需要是全局唯一的。当生成两个不同的数组时,可以使用相同的键。

    key 会作为给 React 的提示,但不会传递给你的组件。如果您的组件中需要使用和 key 相同的值

    Post 组件可以读出 props.id,但是不能读出 props.key。

    const content = posts.map((post) => (
      <Post key={post.id} id={post.id} title={post.title} />
    ));
    

    在 jsx 中嵌入 map()

    function ListItem(props) {
      return <li>{props.value}</li>;
    }
    class ListAndKeys extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          numbers: [1, 2, 3, 4, 5],
        };
      }
    
      render() {
        return (
          <ul>
            {this.state.numbers.map((number, index) => (
              <ListItem key={index} value={number} />
            ))}
          </ul>
        );
      }
    }
    export default ListAndKeys;
    

    React 组件 API

    设置状态:setState 替换状态:replaceState 设置属性:setProps 替换属性:replaceProps 强制更新:forceUpdate 获取 DOM 节点:findDOMNode 判断组件挂载状态:isMounted

    设置状态:setState

    不能在组件内部通过 this.state 修改状态,因为该状态会在调用 setState()后被替换。

    setState()并不会立即改变 this.state,而是创建一个即将处理的 state。setState()并不一定是同步的,为了提升性能 React 会批量执行 state 和 DOM 渲染。

    setState()总是会触发一次组件重绘,除非在 shouldComponentUpdate()中实现了一些条件渲染逻辑。

    import React from "react";
    class ReactAPI extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          name: "小红",
          age: 12,
        };
      }
      handleNameChange = (e) => {
        this.setState({ name: e.target.value }, () => {
          console.log(this.state); // {name: '小红11111', age: 12}
        });
      };
      render() {
        return (
          <div>
            <input
              value={this.state.name}
              type="text"
              onChange={this.handleNameChange}
            />
            <h1>你好:{this.state.name}</h1>
          </div>
        );
      }
    }
    export default ReactAPI;
    

    替换状态:replaceState

    设置属性:setProps

    替换属性:replaceProps

    强制更新:forceUpdate

    获取 DOM 节点:findDOMNode

    判断组件挂载状态:isMounted

    React 组件生命周期

    componentDidMount 所有 AJAX 请求以及 DOM 或状态更新都应在 componentDidMount()方法块中进行编码 shouldComponentUpdate 方法允许我们退出复杂的反应更新生命周期,以避免在每个 re-render 上一次又一次地调用它。

    挂载组件-Mounting

    1. constructor(): 在 React 组件挂载之前,会调用它的构造函数。
    2. getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
    3. render(): render() 方法是 class 组件中唯一必须实现的方法。
    4. componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用。
    class LifeCycle extends React.Component {
      // 在 React 组件挂载之前,会调用它的构造函数。
      constructor(props) {
        super(props);
        this.state = { favoritesite: "runoob" };
        console.log("第一步执行");
      }
      /**
       * 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
       * @param {*} nextProps 下一次props
       * @param {*} nextState 下一次state
       * @returns 默认情况下,它返回true,如果返回false,则不会调用render(),componentWillUpdate()和componentDidUpdate()方法。
       */
      static getDerivedStateFromProps(nextProps, nextState) {
        console.log("第二步执行");
        return { favoritesite: nextProps.favsite };
      }
      // render() 方法是 class 组件中唯一必须实现的方法。
      render() {
        console.log("第三步执行");
        return <h1>我喜欢的网站是 {this.state.favoritesite}</h1>;
      }
      // 在组件挂载后(插入 DOM 树中)立即调用。
      componentDidMount() {
        console.log("第四步执行");
      }
    }
    
    export default LifeCycle;
    

    更新组件-Updating

    class LifeCycle extends React.Component {
      constructor(props) {
        super(props);
        this.state = { favoritesite: "Baidu" };
        console.log("第一步执行-->constructor");
      }
      handleWebChange = (e) => {
        this.setState({ favoritesite: "Google" });
      };
      /**
       * 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
       * @param {*} nextProps 下一次props
       * @param {*} nextState 下一次state
       * @returns 默认情况下,它返回true,如果返回false,则不会调用render(),componentWillUpdate()和componentDidUpdate()方法。
       */
      static getDerivedStateFromProps(nextProps, nextState) {
        console.log("第二步执行-->getDerivedStateFromProps");
        return { favoritesite: nextState.favoritesite };
      }
      // 当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。
      shouldComponentUpdate() {
        console.log("第三步执行-->shouldComponentUpdate");
        return true;
      }
      // render() 方法是 class 组件中唯一必须实现的方法。
      render() {
        console.log("第四步执行-->render");
        return (
          <div>
            <h1>我喜欢的网站是: {this.state.favoritesite}</h1>
            <button onClick={this.handleWebChange}>改变我喜欢的网站为Google</button>
          </div>
        );
      }
      /**
       * 在最近一次渲染输出(提交到 DOM 节点)之前调用。
       * @param {*} prevProps 先前的道具传递到组件
       * @param {*} prevState 组件的先前状态
       * @returns
       */
      getSnapshotBeforeUpdate(prevProps, prevState) {
        console.log("第五步执行-->getSnapshotBeforeUpdate");
        return null;
      }
      /**
       * 在更新后会被立即调用。
       * @param {*} prevProps 先前的道具传递到组件
       * @param {*} prevState 组件的先前状态
       * @param {*} snapshot getSnapshotBeforeUpdate()方法返回的值
       */
      componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("第六步执行-->componentDidUpdate");
      }
    }
    export default LifeCycle;
    

    卸载组件-Unmounting

    class LifeCycle extends React.Component {
      constructor(props) {
        super(props);
        this.state = { show: true };
      }
      delHeader = () => {
        this.setState({ show: false });
      };
      render() {
        let myheader;
        if (this.state.show) {
          myheader = <Child />;
        }
        return (
          <div>
            {myheader}
            <button type="button" onClick={this.delHeader}>
              删除标题组建
            </button>
          </div>
        );
      }
    }
    
    class Child extends React.Component {
      componentWillUnmount() {
        alert("标题组件即将卸载。");
      }
      render() {
        return <h1>Hello Runoob!</h1>;
      }
    }
    
    export default LifeCycle;
    

    React AJAX

    React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据时可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。

    当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。

    import React from "react";
    import $ from "jquery";
    class ReactAjax extends React.Component {
      constructor(props) {
        super(props);
        this.state = { username: "", lastGistUrl: "" };
      }
      componentDidMount() {
        this.serverRequest = $.get(
          this.props.source,
          function (result) {
            var lastGist = result[0];
            this.setState({
              username: lastGist.owner.login,
              lastGistUrl: lastGist.html_url,
            });
          }.bind(this)
        );
      }
    
      componentWillUnmount() {
        this.serverRequest.abort();
      }
      render() {
        return (
          <div>
            <p>{this.state.username} 用户最新的 Gist 共享地址</p>
            <a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a>
          </div>
        );
      }
    }
    export default ReactAjax;
    

    React 表单与事件

    input 的 onChange (示例 1)

    import React from "react";
    class FormEvent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          value: "Hello World",
        };
      }
      changeValue = (event) => {
        this.setState({ value: event.target.value });
      };
      render() {
        return (
          <div>
            <input
              type="text"
              value={this.state.value}
              onChange={this.changeValue}
            />
            <h4>{this.state.value}</h4>
          </div>
        );
      }
    }
    export default FormEvent;
    

    input 的 onChange (示例 2)

    class Content extends React.Component {
      constructor(props) {
        super(props);
        console.log(props);
      }
      render() {
        return (
          <div>
            <input
              type="text"
              value={this.props.myDataProp}
              onChange={this.props.updateStateProp}
            />
            <h4>{this.props.myDataProp}</h4>
          </div>
        );
      }
    }
    class FormEvent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          value: "Hello World",
        };
      }
      changeValue = (event) => {
        this.setState({ value: event.target.value });
      };
      render() {
        return (
          <div>
            <Content
              myDataProp={this.state.value}
              updateStateProp={this.changeValue}
            />
          </div>
        );
      }
    }
    export default FormEvent;
    

    Select 下拉菜单

    class FormEvent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          value: "11",
        };
      }
      handleSubmit = (event) => {
        alert("表单提交了!");
        event.preventDefault();
      };
      handleChange = (event) => {
        this.setState({ value: event.target.value });
      };
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <select value={this.state.value} onChange={this.handleChange}>
              <option value="11">11</option>
              <option value="22">22</option>
              <option value="33">33</option>
              <option value="44">44</option>
            </select>
            <h4>{this.state.value}</h4>
            <input type="submit" value="提交" />
          </form>
        );
      }
    }
    export default FormEvent;
    

    多个表单

    class FormEvent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          isGoing: true,
          value: "11",
        };
      }
      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 htmlFor="">
              <input
                type="checkbox"
                name="isGoing"
                onChange={this.handleInputChange}
                checked={this.state.isGoing}
              />
            </label>
            <label htmlFor="">
              <input
                type="text"
                name="value"
                onChange={this.handleInputChange}
                value={this.state.value}
              />
            </label>
            <h1>{Number(this.state.isGoing)}</h1>
            <h1>{this.state.value}</h1>
          </form>
        );
      }
    }
    export default FormEvent;
    

    React 事件

    当你需要从子组件中更新父组件的 state 时,你需要在父组件通过创建事件句柄 (handleChange) ,并作为 prop (updateStateProp) 传递到你的子组件上

    class Children extends React.Component {
      render() {
        return (
          <div>
            <button onClick={this.props.clickChildren}>点我-我是子组件</button>
            <h4>{this.props.childrenData}</h4>
          </div>
        );
      }
    }
    class FormEvent extends React.Component {
      constructor(props) {
        super(props);
        this.state = { value: "11" };
      }
      clickChildren = () => {
        this.setState({
          value: "我在父组件里面点了子组件的按钮",
        });
      };
      render() {
        return (
          <div>
            <Children
              childrenData={this.state.value}
              clickChildren={this.clickChildren}
            />
          </div>
        );
      }
    }
    export default FormEvent;
    

    React Refs

    React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。

    这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例。

    demo

    class Children extends React.Component {
      render() {
        return (
          <div>
            <h4>我是子组件</h4>
          </div>
        );
      }
    }
    class FormEvent extends React.Component {
      constructor(props) {
        super(props);
      }
      clickBtn = () => {
        this.refs.myInput.focus();
      };
      render() {
        return (
          <div>
            <input type="text" ref="myInput" />
            <Children ref="Children" />
            <button onClick={this.clickBtn}>点击聚焦输入框</button>
          </div>
        );
      }
      componentDidMount() {
        const input = this.refs.myInput;
        console.log(input); // 返回了输入框的 <input type="text">
    
        const Children = this.refs.Children;
        console.log(Children); // 返回组件
        // context: {} 
        // props: {}
        // refs: {}
        // state: null
        // updater: {isMounted: ƒ, enqueueSetState: ƒ, enqueueReplaceState: ƒ, enqueueForceUpdate: ƒ}
        // _reactInternalInstance: {_processChildContext: ƒ}
        // _reactInternals: FiberNode {tag: 1, key: null, stateNode: Children, elementType: ƒ, type: ƒ, …}
        // isMounted
      }
    }
    export default FormEvent;