react基础知识

React is a declarative, efficient, and flexible JavaScript library for building user interfaces.
It lets you compose complex UIs from small and isolated pieces of code called “components”.

注意

concat() 方法可能与你比较熟悉的 push() 方法不太一样,它并不会改变原数组,所以我们推荐使用 concat()
history : history.concat([
{
squares : squares,
}
]),

用slice 拷贝, 用setState来覆盖
const _squares = this.state.squares.slice();
_squares[i] = this.state.isXNext? “X” : “O”;
this.setState({
squares : _squares,
isXNext : !this.state.isXNext
});

js 的匿名函数
onClick = {(i) => this.handleClick(i)}

在 JavaScript 中,数组拥有 map() 方法,该方法通常用于把某数组映射为另一个数组,例如:

const numbers = [1, 2, 3];
const doubled = numbers.map(x => x * 2); // [2, 4, 6]

和scala 很像呀

key 是 React 中一个特殊的保留属性(还有一个是 ref,拥有更高级的特性)。当 React 元素被创建出来的时候,
React 会提取出 key 属性,然后把 key 直接存储在返回的元素上。
虽然 key 看起来好像是 props 中的一个,但是你不能通过 this.props.key 来获取 key。React 会通过 key 来自动判断哪些组件需要更新。组件是不能访问到它的 key 的。

我们强烈推荐,每次只要你构建动态列表的时候,都要指定一个合适的 key。

a. 在 JSX 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式。例如,2 + 2,user.firstName 或 formatName(user) 都是有效的 JavaScript 表达式。

==
const name = ‘Josh Perez’;
const element =

Hello, {name}

;

b. JSX 也是一个表达式
可以在if 和 for 以及return 中使用

c. 使用JSX对某一个属性进行设置
1.字符串
const element =

;
2.jsx表达式
const element = ;
【使用小驼峰命名】

d. Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。
const element = (

Hello, world!

);

to

const element = {
type: ‘h1’,
props: {
className: ‘greeting’,
children: ‘Hello, world!’
}
};

React 通过读取这些对象,然后使用它们来构建 DOM 以及保持随时更新。

<推荐 一个在线的工具 code pen https://codepen.io/pen/ 用react的时候一定要调整setting 为Babel 且引入 //unpkg.com/react/umd/react.development.js //unpkg.com/react-dom/umd/react-dom.development.js>

a - 想要将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入 ReactDOM.render()
b - React 元素是不可变对象。一旦被创建,你就无法更改它的子元素或者属性。
c - React 只更新它需要更新的部分

function tick() {
const element = (


Hello, world!


It is {new Date().toLocaleTimeString()}.



);
ReactDOM.render(element, document.getElementById(‘root’)); // 每次更新dom id 为root的
}

setInterval(tick, 1000);

setInterval react中的Timer,nice!

b.class 组件
class Welcome extends React.Component {
render() {
return

Hello, {this.props.name}

;
}
}

   (二)

react元素不仅可以使DOM的标签,也可以是用户自定义的组件,突然感觉很厉害这个想法
function Welcome(props) {
return

Hello, {props.name}

;
}

const element = ;
ReactDOM.render(
element,
document.getElementById(‘root’)
);

Welcome 是一个函数组件, 把name="Sara"当做一个属性参数传入 function中 实际返回的是

	(三)

组件可以相互组合嵌套

function Welcome(props) {
return

Hello, {props.name}

;
}

function App() {
return (






);
}

ReactDOM.render(
,
document.getElementById(‘root’)
);

	(四)

所有 React 组件都必须像纯函数一样保护它们的 props 不被更改!!!!

class Clock extends React.Component {
constructor(props) { ================= 构造函数
super(props);
this.state = {date: new Date()}; ======== 设置state
}

componentDidMount() { ========= 在加入完成DOM后 会调用挂载
this.timerID = setInterval( ==== 设置Timer
() => this.tick(),
1000
);
}

componentWillUnmount() { ========== 移除DOM后 会调用卸载
clearInterval(this.timerID);
}

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

render() { ======== 渲染内容
return (


Hello, world!


It is {this.state.date.toLocaleTimeString()}.



);
}
}

ReactDOM.render(
, ========== 加入到DOM中 root 下, 调用构造函数
document.getElementById(‘root’)
);

尽管 this.props 和 this.state 是 React 本身设置的,且都拥有特殊的含义,但是其实你可以向 class 中随意添加不参与数据流(比如计时器 ID)的额外字段。

	(1)
不要直接修改 State 使用setState
	(2)
State 的更新可能是异步的

this.setState((state, props) => ({
	counter: state.counter + props.increment
}));
传入上一次的state来更新state

HTML

Activate Lasers

React

Activate Lasers

在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault 。
function handleClick(e) {
e.preventDefault();
console.log(‘The link was clicked.’);
}

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

// 为了在回调中使用 `this`,这个绑定是必不可少的, 如果不bind那么在回调的里面找不到this,这个和javascript有关系,以后可以深究 https://zh-hans.reactjs.org/docs/handling-events.html
this.handleClick = this.handleClick.bind(this);

}

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

render() {
return (

{this.state.isToggleOn ? ‘ON’ : ‘OFF’}

);
}
}

ReactDOM.render(
,
document.getElementById(‘root’)
);

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row
<button onClick={this.deleteRow.bind(this, id)}>Delete Row
bind了this,也可以在构造函数中bind

上述两种方式是等价的,分别通过箭头函数和 Function.prototype.bind 来实现。

在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (


Hello!


{unreadMessages.length > 0 &&


You have {unreadMessages.length} unread messages.


}

);
}

const messages = [‘React’, ‘Re: React’, ‘Re:Re: React’];
ReactDOM.render(
,
document.getElementById(‘root’)
);

之所以能这样做,是因为在 JavaScript 中,true && expression 总是会返回 expression, 而 false && expression 总是会返回 false。

阻止条件渲染
若要完成此操作,你可以让 render 方法直接返回 null,而不进行任何渲染。

key
key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。

function ListItem(props) {
// 正确!这里不需要指定 key:
return

  • {props.value}
  • ;
    }

    function NumberList(props) {
    const numbers = props.numbers;
    const listItems = numbers.map((number) =>
    // 正确!key 应该在数组的上下文中被指定

    );
    return (


    • {listItems}

    );
    }

    定义组件的时候不要制定Key,在数组使用的时候使用Key

    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 (






    );
    }
    }

    受控组件
    在 HTML 中,表单元素(如、 和 )之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。

    我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。
    渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

    控制 + 渲染

    在受控组件上指定 value 的 prop 可以防止用户更改输入。如果指定了 value,但输入仍可编辑,则可能是意外地将value 设置为 undefined 或 null。

    非受控组件
    https://zh-hans.reactjs.org/docs/uncontrolled-components.html

    切记: 调用 this.setState() 进而请求 React 重新渲染自己本身。且是逐层向下

    例子: 温度转换的一个例子
    对应上面提到的x或y
    class TemperatureInput extends React.Component {
    constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this); 回调要bind
    }

    handleChange(e) {
    this.props.onTemperatureChange(e.target.value); 回调中调用了props参数中的回调,这个回调是上层组件传进来的
    }

    render() {
    const temperature = this.props.temperature; 渲染时也是用的上层组件传进来的参数
    const scale = this.props.scale;
    return (

    Enter temperature in {scaleNames[scale]}:


    );
    }
    }

    相当于下层组件用上层组件提供的参数和回调
    参数 — 进行渲染
    回调 — 更新参数,上层更新完参数,出发渲染(setstate触发)

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

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

    function tryConvert(temperature, convert) {
    const input = parseFloat(temperature);
    if (Number.isNaN(input)) {
    return ‘’;
    }
    const output = convert(input);
    const rounded = Math.round(output * 1000) / 1000; 四舍五入
    return rounded.toString();
    }

    看一下对应的z
    class Calculator extends React.Component {
    constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = {temperature: ‘’, scale: ‘c’};
    }

    handleCelsiusChange(temperature) {
    this.setState({scale: ‘c’, temperature});
    }

    handleFahrenheitChange(temperature) {
    this.setState({scale: ‘f’, temperature});
    }

    render() {
    const scale = this.state.scale;
    const temperature = this.state.temperature;
    const celsius = scale === ‘f’ ? tryConvert(temperature, toCelsius) : temperature; 进行温度的转换
    const fahrenheit = scale === ‘c’ ? tryConvert(temperature, toFahrenheit) : temperature;

    return (
      <div>
        <TemperatureInput
          scale="c"
          temperature={celsius}
          onTemperatureChange={this.handleCelsiusChange} />
    
        <TemperatureInput
          scale="f"
          temperature={fahrenheit}   传进去温度
          onTemperatureChange={this.handleFahrenheitChange} />  传进去回调
    
        <BoilingVerdict
          celsius={parseFloat(celsius)} />
    
      </div>
    );
    

    }
    }

    好处:
    在 React 应用中,任何可变数据应当只有一个相对应的唯一“数据源”。通常,state 都是首先添加到需要渲染数据的组件中去。
    然后,如果其他组件也需要这个 state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。

    虽然提升 state 方式比双向绑定方式需要编写更多的“样板”代码,但带来的好处是,排查和隔离 bug 所需的工作量将会变少。
    由于“存在”于组件中的任何 state,仅有组件自己能够修改它,因此 bug 的排查范围被大大缩减了。此外,你也可以使用自定义逻辑来拒绝或转换用户的输入。

    官网建议我们使用开发者工具来排错: https://github.com/facebook/react-devtools (好像已经merge到其他分支了,有空再看吧)

    包含关系:

    function FancyBorder(props) {
    return (
    <div className={‘FancyBorder FancyBorder-’ + props.color}>
    {props.children} =================== 这一点可以吧任意组件传入做子组件

    );
    }

    function WelcomeDialog() {
    return (
    ============= 1

    ======传入了h1 和 p 两个组件
    Welcome



    Thank you for visiting our spacecraft!



    );
    }
    结合我们前面的经验: 其实我们也可以在 1 初设定id,
    通过下面的方法来重新渲染
    ReactDOM.render(
    主键,
    document.getElementById(‘root’)
    );

    简单修改后 =>
    (不推荐这样使用,个人觉得会 在结构上看不清楚,还是 {props.children} 吧)
    function FancyBorder(props) {
    return (
    <div className={‘FancyBorder FancyBorder-’ + props.color} id = {props.id}>

    );
    }

    const componentId = “fb”;

    function Content(){
    return (


    Welcome1


    );
    }

    function WelcomeDialog() {
    var componentFB =

    </FancyBorder>;
    

    return componentFB;
    }

    ReactDOM.render(
    ,
    document.getElementById(‘root’)
    );

    ReactDOM.render(
    ,
    document.getElementById(componentId)
    );

    例子二: 预留几个模块

    function SplitPane(props) {
    return (



    {props.left} ====== left 组件


    {props.right} ====== right 组件


    );
    }

    function App() {
    return (
    <SplitPane
    left={

    }
    right={

    } />
    );
    }

    特例关系
    个人觉得用特许关系这个词描述的不是很恰当,不如说是组件直接的封装调用。。。可能我理解的也不对

    例子:
    渲染Dialog组件需要上层组件传入title 和 message,同时还留了children给扩展
    function Dialog(props) {
    return (


    {props.title}



    {props.message}


    {props.children}

    );
    }

    这里提一句什么时候用class 什么时候用function, 当一个组件需要控制某个变量的状态的时候,那么就需要用class,需要用state来储存
    可以这么理解,静态的一些组件,比如说logo,没必要更新什么状态,function足够了,再比如登录组件,这个时候需要记录用户名,密码甚至发起ajax请求那么就需要用class

    class SignUpDialog extends React.Component {
    constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this); ==== 绑定this到回调上
    this.handleSignUp = this.handleSignUp.bind(this);
    this.state = {login: ‘’}; ==== 记录用户名
    }

    render() {
    return (
    <Dialog title=“Mars Exploration Program” ========== 向dialog组件传入内容
    message=“How should we refer to you?”>

        <button onClick={this.handleSignUp}>
          Sign Me Up!
        </button>
      </Dialog>
    );
    

    }

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

    handleSignUp() {
    alert(Welcome aboard, ${this.state.login}!);
    }
    }

    官网总结:

    在 Facebook,我们在成百上千个组件中使用 React。我们并没有发现需要使用继承来构建组件层次的情况。
    如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们。

    me: 合着就是你可以用继承做一个工具包,到了写页面的时候不要在用继承了!

    React 哲学 (设计的一般思路)

    第一步:将设计好的 UI 划分为组件层级
    如果你是和设计师一起完成此任务,那么他们可能已经做过类似的工作,所以请和他们进行交流!他们的 Photoshop 的图层名称可能最终就是你编写的 React 组件的名称!
    (很喜欢这种感觉)

    第二步:用 React 创建一个静态版本
    在构建应用的静态版本时,我们需要创建一些会重用其他组件的组件,然后通过 props 传入所需的数据。props 是父组件向子组件传递数据的方式。
    即使你已经熟悉了 state 的概念,也完全不应该使用 state 构建静态版本。state 代表了随时间会产生变化的数据,应当仅在实现交互时使用。所以构建应用的静态版本时,你不会用到它

    第三步:确定 UI state 的最小(且完整)表示
    通过问自己以下三个问题,你可以逐个检查相应数据是否属于 state:

    1. 该数据是否是由父组件通过 props 传递而来的?如果是,那它应该不是 state。 (上层管理)
    2. 该数据是否随时间的推移而保持不变?如果是,那它应该也不是 state。 (静态数据)
    3. 你能否根据其他 state 或 props 计算出该数据的值?如果是,那它也不是 state。 (可以计算的)

    第四步:确定 state 放置的位置

    React 中的数据流是单向的,并顺着组件层级从上往下传递
    对于应用中的每一个 state:

    找到根据这个 state 进行渲染的所有组件。
    找到他们的共同所有者(common owner)组件(在组件层级上高于所有需要该 state 的组件)。
    该共同所有者组件或者比它层级更高的组件应该拥有该 state。
    如果你找不到一个合适的位置来存放该 state,就可以直接创建一个新的组件来存放该 state,并将这一新组件置于高于共同所有者组件层级的位置

    第五步:添加反向数据流
    一句话设置回调来反向修改数据

    终于看完了!!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值