React学习1——核心概念

1. Hello World

最简易的React实例如下:

ReactDOM.render(
	<h1>Hello World!</h1>,
	document.getElementById('root')
);

2. JSX

JSX直观印象:<h1>ello, {name} !</h1>或者 <Welcome name="vivian" />

  • JSX表示对象(React 元素),JSX等价于React.createElement()函数调用
// 以下两种代码完全等价
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

const element = React.createElement( // 会创建出一个对象
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
  • JSX是一个表达式:可以将JSX赋值给变量、可以作为入参出参
  • 可以在JSX中嵌入表达式,通过大括号{}的形式
// JSX作为变量
const element = <img src={user.avatarUrl} />;
const element = <div tabIndex="1">hhh</div>;
// 函数中返回JSX
function fun() {
	return <h1>hhh</h1>;
}

3. 元素渲染

按照自己的理解,React元素相当于JSX,直观理解:<h1>ello, {name} !</h1>或者 <Welcome name="vivian" />

<div id="root"></div>是根节点,该节点内的内容将由React DOM管理,将React元素渲染到根节点中:

const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));

React 元素是不可变的,一旦被创建,你就无法更改它的子元素或者属性。因此,想要更新UI只能重新渲染,即再次执行ReactDOM.render()(当然不止这种方式,class组件中的render也是)。注意每一次执行ReactDOM.render(),React
DOM会只更新变化的部分(只进行必要的更新)。

4. 组件 & Props

组件:传入props,传出React元素

函数组件

function Welcome(props) {
	return <h1>Hello, {props.name}</h1>;
}

class组件

class Welcome extends React.Component {
	render() {
		return <h1>Hello, {this.props.name}</h1>;
	}
}
  • 组件名称必须以大写字母开头
  • 纯函数定义:不会更改入参,且多次调用下相同入参始终返回相同的结果。
  • 所有 React 组件都必须像纯函数一样保护它们的 props 不被更改

5. State & 生命周期

  • state:class组件私有属性,可以通过setState()来进行变更
  • 生命周期函数:componentDidMountcomponentWillUnmount
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
  // 组件已经被渲染到 DOM 中后运行
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  // 组件被删除的时候运行
  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

使用setState注意点

  • state的更新是合并的。
  • state的更新可能是异步的,不要依赖this.state和this.props来更新下一个状态
// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) = ({
	counter: state.counter + props.increment
}));

6. 事件处理

React元素事件处理与传统HTML的区别

// 传统的HTML
<button onclick="activateLasers()">
  Activate Lasers
</button>
// React
<button onClick={activateLasers}>
  Activate Lasers
</button>

//阻止默认行为:在React中不能通过返回false的方式,必须显式使用preventDefault
//传统的HTML
<a href="#" onclick="console.log('The link was clicked.'); return false">
  Click me
</a>
// React
function ActionLink() {
  function handleClick(e) { //e 是一个合成事件
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

如何正确绑定事件

法一:直接在constructor上绑定这个事件

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    //法一: 为了在回调中使用 `this`,这个绑定是必不可少的,如果没有绑定,则在调用这个函数的时候this的值为undefined
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(state => ({
      isToggleOn: !state.isToggleOn
    }));
  }

  render() {
    return (
      // 法一:
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

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

法二:使用 class fields 正确的绑定回调函数

class LoggingButton extends React.Component {
  // 此语法确保 `handleClick` 内的 `this` 已被绑定。
  // 注意: 这是 *实验性* 语法。
  handleClick = () => { // 在此处使用了箭头函数
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

法三(在公司里最常用):在回调中使用箭头函数。
此语法问题在于每次渲染 LoggingButton 时都会创建不同的回调函数。在大多数情况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题。

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // 此语法确保 `handleClick` 内的 `this` 已被绑定。
    return (
      // 使用箭头函数
      <button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }
}

向事件传递参数

// 在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

7. 条件渲染

  • if
  • &&
  • 三目运算符: condition ? true : false
// if
function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}
// &&
render() {
  return (
    {unreadMessages.length > 0 && <h1>hhh</h1>}
   )
}
// 三目运算符
render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}

8. 列表 & Key

  • key帮助React识别哪些元素改变了,比如被添加或删除。不是作为属性传递。
  • key值需要在该数组中独一无二,一般选用元素的id,不建议使用索引来作为key值,因为项目的顺序可能发生变化,导致一些问题。
  • 一个好的经验法则是:在map() 方法中的元素需要设置 key 属性。
function NumberList(props) {
  const numbers = props.numbers;
  // 使用map渲染一个列表,注意需要添加key
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

9. 表单

受控组件

  • 受控组件:state是表单输入元素的唯一数据源,控制着用户输入过程中表单发生的操作。
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('提交的名字: ' + this.state.value);
    event.preventDefault(); // 阻止系统默认行为:提交表单后浏览新页面
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          名字:
          //input的数据展示来源于state,当输入内容改变时,也会更改state并展示出来,这就是受控组件
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}
  • input标签
<input type="text" value={this.state.value} onChange={this.handleChange} />

当需要处理多个 input 元素时,我们可以给每个元素添加 name属性,并让处理函数根据 event.target.name的值选择要执行的操作。

  • textarea标签
<textarea value={this.state.value} onChange={this.handleChange} />
  • select标签
<select value={this.state.value} onChange={this.handleChange}>
	<option value="grapefruit">葡萄柚</option>
	<option value="lime">酸橙</option>
	<option value="coconut">椰子</option>
	<option value="mango">芒果</option>
</select>
// 多选
<select multiple={true} value={['B', 'C']}>

有时候使用受控组件会很麻烦,因为需要为数据变化的每种方式都编写事件处理函数,并通过一个React组件传递所有的输入state,也可以使用非受控组件,这是实现输入表单的另一种方式。

10. 状态提升

通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。

11. 组合 vs 继承

React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用

  • React当中没有槽(slot)的概念限制,你可以将任何东西作为props进行传递,包括基本数据类型、React元素以及函数

组合的常见使用方式:包含和特例

function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children} 
    </div>
  );
}

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      //直接写在组件内的内容作为props.children传递,
      //如果想传入多个ui空位,可以自定义传入的props
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
    </FancyBorder>
  );
}
// Dialog的特例
function WelcomeDialog() {
  return (
    <Dialog
      title="Welcome"
      message="Thank you for visiting our spacecraft!" />
  );
}

12. React 哲学

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值