组件实例三大核心属性之一 props & refs

props

展开运算符

" … " 展开运算符可以和数组匹配使用

  1. 可以展开一个数组
let arr1 = [1234]
console.log(...arr1)
let arr2 = [1,2,3,4]
  1. 也可以用于连接两个数组
let arr1 = [1234]
let arr2 = [1,2,3,4]
let arr3 = [...arr1...arr2]
console.log(arr3)
  1. 传参
    在函数中使用
function sum(...numbers) {
	//numbers传进来一个数组
	return numbers.reduce( (preValue,currentValue) => {
		return preValue + currentValue;
	})
}
  1. 构造字面量对象时使用展开语法
    展开运算符不能展开一个对象,但是外面包上{},就可以复制一个对象
let person = {name:'Tome',age:'20'}
person2 = {...person}
5. 复制对象时合并属性
let person3 = {...person,name:'jack',address:'地球'}

批量传递props(批量传递标签属性)

    <script type="text/babel">
      //1. 创建组件
      class Person extends React.Component {
        render() {
          const { name, age, sex } = this.props;
          return (
            <ul>
              <li>姓名:{name}</li>
              <li>性别:{sex}</li>
              <li>年龄:{age}</li>
            </ul>
          );
        }
      }
      const p = { name: "TOME", sex: "male", age: "20" };
      //渲染组件到页面
      //babel和react允许...展开运算符展开对象,但是仅仅适用于标签属性的传递
      ReactDOM.render(<Person {...p} />, document.getElementById("test"));
    </script>

对props进行限制

组件自身propTypes属性,可以进行类型的限制和必填限制。
组件自身的defaultProps属性,可以进行默认值的设置。

    <script type="text/babel">
      //1. 创建组件
      class Person extends React.Component {
        render() {
          const { name, age, sex } = this.props;
          return (
            <ul>
              <li>姓名:{name}</li>
              <li>性别:{sex}</li>
              <li>年龄:{age}</li>
            </ul>
          );
        }
      }
      //对标签属性进行类型、必要性的限制
      Person.propTypes = {
        name: PropTypes.string.isRequired,//name设置必填,且为字符串
        sex: PropTypes.string,//限制sex为字符串
        age: PropTypes.number,//限制age为数字
      };
      //指定默认值
      Person.defaultProps = {
        sex: "male",//sex设置默认值
      };
      const p = { name: "TOME", sex: "male", age: "20" };
      //渲染组件到页面
      //babel和react允许...展开运算符展开对象,但是仅仅适用于标签属性的传递
      ReactDOM.render(<Person {...p} />, document.getElementById("test"));
    </script>

props的简写

【!!props是只读的!!】
this.props.name = “TTome”//这行代码会报错
将限制属性写在类中,
添加到类对象上,在属性前加static

class Person extends React.Component {
        render() {
          const { name, age, sex } = this.props;
          return (
            <ul>
              <li>姓名:{name}</li>
              <li>性别:{sex}</li>
              <li>年龄:{age}</li>
            </ul>
          );
        }
        //对标签属性进行类型、必要性的限制
        static propTypes = {
          name: PropTypes.string.isRequired, //name设置必填,且为字符串
          sex: PropTypes.string, //限制sex为字符串
          age: PropTypes.number, //限制age为数字
        };
        //指定默认值
        static defaultProps = {
          sex: "male", //sex设置默认值
        };
      }

类式组件的构造器

构造器是否接收props,是否传递super,
取决于:是否希望在构造器中通过this访问props

不接收props,不传递super(props),this.props在构造函数中可能会出现未定义的bug

如果在构造函数中不通过this.props访问props,那写不写无所谓。

函数式组件使用props

函数式组件由于是函数,可以传递参数,可以使用props

function Person(props) {
        console.log(props);
        const { name, sex } = props;
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{sex}</li>
          </ul>
        );
      }
      //对标签属性进行类型、必要性的限制
      Person.propTypes = {
        name: PropTypes.string.isRequired, //name设置必填,且为字符串
        sex: PropTypes.string, //限制sex为字符串
        age: PropTypes.number, //限制age为数字
      };
      //指定默认值
      Person.defaultProps = {
        sex: "male", //sex设置默认值
      };
      const p = { name: "TOME", sex: "male", age: "20" };
      //渲染组件到页面
      //babel和react允许...展开运算符展开对象,但是仅仅适用于标签属性的传递
      ReactDOM.render(
        <Person name="TOME" sex="male" />,
        document.getElementById("test")
      );

【不要把propTypes写成protoType了!!】

总结props

  • 每个对象都会有props属性
  • 组件标签的所有属性都保存在props中
  • 通过标签属性从组件外向组件内传递变化的数据
  • 组件内部不能修改props数据,props数据是只读的

refs

字符串形式的ref

已经不被推荐使用,效率不高,以后更新有可能直接废弃掉

      class Demo extends React.Component {
        showData = () => {
          console.log(this.refs.input1);
          const { input1 } = this.refs;
          alert(input1.value);
        };
        showData2 = () => {
          console.log(this.refs.input1);
          const { input2 } = this.refs;
          alert(input2.value);
        };
        render() {
          return (
            <div>
              <input ref="input1" type="input" placeholder="点击按钮提示数据" />
              &nbsp;&nbsp;
              <button ref="button1" onClick={this.showData}>
                点击按钮提示左侧数据
              </button>
              &nbsp;
              <input
                onBlur={this.showData2}
                ref="input2"
                type="input"
                placeholder="失去焦点提示数据"
              />
            </div>
          );
        }
      }
      ReactDOM.render(<Demo />, document.getElementById("test"));

回调形式的ref

箭头函数没有this,this向外找,找到了组件实例对象。
ref={© => (this.input1 = c)}这个回调函数的调用者是当前节点,不是我们自己调用传参,所以c接收当前节点,并且把这个节点放在实例对象的input1属性上

<script type="text/babel">
      class Demo extends React.Component {
        showData = () => {
          const { input1 } = this;
          alert(input1.value);
        };
        showData2 = () => {
          const { input2 } = this;
          alert(input2.value);
        };
        render() {
          return (
            <div>
              <input
                ref={(c) => (this.input1 = c)}
                type="text"
                placeholder="点击按钮提示数据"
              />
              &nbsp;&nbsp;
              <button onClick={this.showData}>点击按钮提示左侧数据</button>
              &nbsp;
              <input
                onBlur={this.showData2}
                ref={(c) => (this.input2 = c)}
                type="text"
                placeholder="失去焦点提示数据"
              />
            </div>
          );
        }
      }
      ReactDOM.render(<Demo />, document.getElementById("test"));
    </script>

回调函数中ref调用次数的问题

  • 如果ref回调函数是以内联函数的方式定义的,在更新过程中会被执行两次,第一次传入的参数是null,第二次传入的参数才是节点。
  • 这是因为在每次渲染时会创建要给新的函数实例,所以React清空旧的ref并且设置新的
  • 通过将ref回调函数定义成class的绑定函数的方式可以避免上述问题,但是大多数情况下这是无关紧要的。
<script type="text/babel">
      class Demo extends React.Component {
        state = { isHot: false };
        showInfo = () => {
          const { input1, btn } = this;
          alert(input1.value);
        };
        changeWeather = () => {
          const { isHot } = this.state;
          this.setState({ isHot: !isHot });
        };
        saveInput = (c) => {
          this.input1 = c;
          console.log("@", c);
        };
        render() {
          const { isHot } = this.state;
          return (
            <div>
              <h2>今天天气很 {isHot ? "炎热" : "凉爽"}</h2>
              {/*<input
                ref={(c) => {
                  console.log("@",c);
                  this.input1 = c;
                }}
                type="text"
              />*/}
              {/*内联形式回调ref*/}
              <input ref={this.saveInput} type="text" />
              {/*类绑定形式定义ref*/}
              <br />
              <br />
              <button ref={(c) => (this.btn = c)} onClick={this.showInfo}>
                点我提示输入的数据
              </button>
              <button onClick={this.changeWeather}>点我改变天气</button>
            </div>
          );
        }
      }
      ReactDOM.render(<Demo />, document.getElementById("test"));
    </script>

createRef

  • React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点
  • 该容器是专人专用的,一个容器只能存一个
  • 用几个ref就得创建几个容器
  • 有点麻烦,但是这种方式是目前react最推荐使用的
<script type="text/babel">
      myRef = React.createRef();
      myRef2 = React.createRef();

      class Demo extends React.Component {
        showData = () => {
          const { input1 } = this.myRef.current;
          alert(input1.value);
        };
        showData2 = () => {
          const { input2 } = this.myRef2.current;
          alert(input2.value);
        };
        render() {
          return (
            <div>
              <input
                ref={this.myRef}
                type="text"
                placeholder="点击按钮提示数据"
              />
              &nbsp;&nbsp;
              <button onClick={this.showData}>点击按钮提示左侧数据</button>
              &nbsp;
              <input
                onBlur={this.shoData2}
                ref={this.myRef2}
                type="text"
                placeholder="失去焦点提示数据"
              />
            </div>
          );
        }
      }
      ReactDOM.render(<Demo />, document.getElementById("test"));
    </script>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值