React的Hello World

2020-05-11  本文已影响0人  李霖弢
VSCode配置语法高亮

安装Babel JavaScript插件

创建项目

npx create-react-app my-app
cd my-app
npm start
其他还有

npm run build打包项目
npm run eject弹射配置文件
此外在package.json中添加"homepage": ".",可以让打包后的资源路径都变为相对index.html


JSX

JSX并不是单纯的将{}中内容替换后的HTML

所有JSX其实都是React.createElement() 的语法糖,通过Babel 可以进行转义。

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

等同于

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

渲染

通过render方法将react元素初始化并渲染到页面上

  ReactDOM.render(
    element,
    document.getElementById('root')
  );

其中element可以直接为上文中新建的元素,也可以为元素对应的组件标签,如<MyTest />


组件

接受任意的属性作为入参(即 props),并返回用于描述页面展示内容的 React 元素。

函数组件与 class 组件
function Welcome(props) {
  return element;
}

class组件中每次组件更新都会重新触发render

class Welcome extends React.Component {
  render() {
    return element;
  }
}
react元素也可以是自定义组件
const name="Sara";
function Welcome_Fn(props) {
  function speak(e) {
    e.preventDefault();
    alert(this.props.name);
  }
  return <h1 onClick={speak}>Hello, {props.name}</h1>;
}

class Welcome_Class extends React.Component {
  speak() {
    alert(this.props.name);
  }
  render() {
    return <div onClick={onClick=()=>this.speak()}>Hello, {this.props.name}</div>;
  }
}

const element = <Welcome_Class name="Sara" />;
ReactDOM.render(
  //element,
  //<Welcome_Class/>,
  //<Welcome_Fn/>,
  //new Welcome_Class({name}),
  //new Welcome_Fn({name}),
  <div>Hello, {name}</div>,
  document.getElementById('root')
);
props
state
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
  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')
);
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));
//或
this.setState(function(state, props) {
  return {
    counter: state.counter + props.increment
  };
});
自上而下的单向数据流

多重组件嵌套时,通常将父的state传递给子的props,任何的 state总是所属于特定的组件,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。


事件处理

React 事件的命名采用小驼峰式而非纯小写,且在JSX中需传入一个事件处理函数。

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}
使用class组件时的方法内this指向问题

可类比以下操作

class A {
  handleClick1 = () => {
    console.log(this, "handleClick1");
  }
  handleClick2() {
    console.log(this, "handleClick2");
  }
  render() {
    window.addEventListener("click", this.handleClick1);//A
    window.addEventListener("click", this.handleClick2);//window
  }
}
new A().render();

因此有三种方法避免this指向问题

  1. 构造函数中使用bind
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  1. 使用class fields语法
  handleClick = () => {
    console.log(this);
  }
  1. 在回调中使用()=>bind
<button onClick={(e) => this.handleClick(id, e)}>Click me</button>
handleClick(id,event){
  ...
}
<button onClick={this.handleClick.bind(this, id)}>Click me</button>

条件渲染

当不想进行任何渲染时,可以return null

&&
function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}

?:
render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}

列表 & Key

列表中的内容是一个React元素的数组,以下两种方式均可生成一个列表
注意列表中必须有key,未指定key时key默认为索引值

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}
function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );
}

表单

React中未实现双向绑定

受控组件
class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      fruit: "lime"
    };

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

  handleChange(event) {
    const target = event.target;
    const value = target.name === 'isGoing' ? target.checked : target.value;
    const name = target.name;
    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleChange} />

          <select name="fruit" value={this.state.fruit} onChange={this.handleChange}>
            <option value="grapefruit">葡萄柚</option>
            <option value="lime">酸橙</option>
            <option value="coconut">椰子</option>
            <option value="mango">芒果</option>
          </select>
      </form>
    );
  }
}
非受控组件
class FileInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.fileInput = React.createRef();
  }
  handleSubmit(event) {
    event.preventDefault();
    alert(
      `Selected file - ${this.fileInput.current.files[0].name}`
    );
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Upload file:
          <input type="file" ref={this.fileInput} />
        </label>
        <br />
        <button type="submit">Submit</button>
      </form>
    );
  }
}

ReactDOM.render(
  <FileInput />,
  document.getElementById('root')
);
使用 Formik

状态提升

将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,以实现共享 state

实现方式

父元素通过props将待展示的值和该值变化时的回调方法传给子元素。子元素调用该回调时,父元素对应state改变,并重新影响各个子元素。以此实现兄弟元素间的值共享。


打包

在package.json中加入"homepage": ".",即可使打包后资源路径变为相对路径(否则默认为绝对路径)。

上一篇 下一篇

猜你喜欢

热点阅读