/**
* @author shj
* @file react index
*/
import React from 'react';
import ReactDOM from 'react-dom';
// hello world 显示
const name = 'shj';
const element = <h2> react {name}</h2>;
ReactDOM.render(
element,
document.getElementById('root')
);
// 对象引用
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let p1 = new Person('张三', 12);
let ele = (
<div>
<h1> hello ,{p1.name}</h1>
</div>
);
ReactDOM.render(ele, document.getElementById('root'));
// 调用定时任务 元素渲染只能通过覆盖来实现
let msg = '秒表';
function times() {
ele = (
<div>
<h1>react {msg}</h1>
<h2> time: {new Date().toLocaleTimeString()}</h2>
</div>
);
ReactDOM.render(ele, document.getElementById('root'));
}
setInterval(times, 1000000);
// 组件与props
/**
* 当 React 元素为用户自定义组件时,
* 它会将 JSX 所接收的属性(attributes)转换为单个对象传递给组件,
* 这个对象被称之为 “props”。
* 注意: 组件名称必须以大写字母开头。
React 会将以小写字母开头的组件视为原生 DOM 标签。
例如,<div /> 代表 HTML 的 div 标签,而 <Welcome />
则代表一个组件,并且需在作用域内使用 Welcome。
*/
class Welcome extends React.Component {
render() {
return <h1>hello ,{this.props.name} </h1>;
}
}
ele = <Welcome name = "baidu"/>;
ReactDOM.render(ele, document.getElementById('root'));
/**
* 我们调用 ReactDOM.render() 函数,并传入 <Welcome name="baidu" /> 作为参数。
React 调用 Welcome 组件,并将 {name: 'baidu'} 作为 props 传入。
Welcome 组件将 <h1>Hello, baidu</h1> 元素作为返回值。
React DOM 将 DOM 高效地更新为 <h1>Hello, baidu</h1>。
*/
// 组合组件
class App extends React.Component {
render() {
return (
<div>
<Welcome name = '张1三'/>
<Welcome name = '张四'/>
<Welcome name = '张五'/>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
// 提取组件 将比较复杂的组件,拆分为多个小组件
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{(props.date)}
</div>
</div>
);
}
class Avatar extends React.Component {
render() {
return (
<span className="Avatar">
{this.props.user.avatarUrl}{this.props.user.name}
</span>
);
}
}
class UserInfo extends React.Component {
render() {
return (
<div className="UserInfo">
<Avatar user={this.props.user} />
<div className="UserInfo-name">
{this.props.user.name}
</div>
</div>
);
}
}
class MyComp extends React.Component {
render() {
return (
<div className="Comment">
<UserInfo user ={this.props.comp.user}/>
<div className="Comment-text">
{this.props.comp.text}
</div>
<div className="Comment-date">
{(this.props.comp.date)}
</div>
</div>
);
}
}
let comp = {};
let user = {};
user.avatarUrl = 'aaa';
user.name = '无图';
comp.user = user;
comp.text = 'mytext';
comp.date = new Date().toLocaleTimeString();
ReactDOM.render(<MyComp comp ={comp}/>, document.getElementById('root'));
// 所有 React 组件都必须像纯函数一样保护它们的 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>Clock</h1>
<h1> Time : {this.state.date.toLocaleTimeString()}</h1>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
/**
* 构造方法是唯一直接设置state的入口
* 只能通过setState() 改变state state ='' 并不能改变
* state除了拥有并设置了它的组件,其他组件都无法访问
* 这通常会被叫做“自上而下”或是“单向”的数据流。
* 任何的 state 总是所属于特定的组件,
* 而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件
*/
class App1 extends React.Component {
render() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
);
}
}
// 每个 Clock 组件都会单独设置它自己的计时器并且更新它。
ReactDOM.render(
<App1 />,
document.getElementById('root')
);
// 事件处理
class Buttons extends React.Component {
constructor(props) {
super(props);
this.state = {isOn: true};
// 为了在回调中使用 this ,必须绑定
this.clicks = this.clicks.bind(this);
}
clicks() {
this.setState(prevState => ({isOn: !prevState.isOn
}));
}
render() {
return (
<button onClick={this.clicks}>
{this.state.isOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Buttons />,
document.getElementById('root')
);
// <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
// 条件渲染
class Comp1 extends React.Component {
render() {
return (
<h1> comp1 </h1>
);
}
}
class Comp2 extends React.Component {
render() {
return (
<h1> comp2 </h1>
);
}
}
class Show extends React.Component {
render() {
if (this.props.flag) {
return <Comp1/>;
}
else {
return <Comp2/>;
}
}
}
ReactDOM.render(
<Show flag ={false}/>,
document.getElementById('root')
);
// 元素变量
class Login extends React.Component {
render() {
return (
<button onClick={this.props.onClick}>
LOgin
</button>
);
}
}
class Logout extends React.Component {
render() {
return (
<button onClick={this.props.onClick}>
Logout
</button>
);
}
}
class LogController extends React.Component {
constructor(props) {
super(props);
this.loginClock = this.loginClock.bind(this);
this.logoutClock = this.logoutClock.bind(this);
this.state = {flag: false};
}
loginClock() {
this.setState({flag: true});
}
logoutClock() {
this.setState({flag: false});
}
render() {
const flag = this.state.flag;
// let button;
// if (flag) {
// button = <Login onClick ={this.logoutClock}/>;
// }
// else {
// button = <Logout onClick ={this.loginClock}/>;
// }
// return (
// <div>
// <Show flag ={flag}/>
// {button}
// </div>
// );
// 使用三目运算符
return (
<div>
{flag ? (
<Login onClick ={this.logoutClock}/>
) : (
<Logout onClick ={this.loginClock}/>)
}
</div>
);
}
}
ReactDOM.render(
<LogController/>,
document.getElementById('root')
);
/**
* 在 JavaScript 中,true && expression 总是会返回 expression, 而 false && expression 总是会返回 false。
因此,如果条件是 true,&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。
* 在极少数情况下,你可能希望能隐藏组件,即使它已经被其他组件渲染。
* 若要完成此操作,你可以让 render 方法直接返回 null,而不进行任何渲染。
*/
// 列表
const arr = [7, 2, 3, 4, 5];
let arrItem = arr.map(number => <li >{number}</li>);
ReactDOM.render(
<ul>{arrItem}</ul>,
document.getElementById('root')
);
// key
class Numbers extends React.Component {
constructor(props) {
super(props);
this.state = {item: props.items};
}
render() {
let arrItem = this.state.item.map(number => <li key = {number.toString()}>{number}</li>);
return (
<ul >{arrItem}</ul>
);
}
}
ReactDOM.render(
<Numbers items={arrItem}></Numbers>,
document.getElementById('root')
);
/**
* key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识
* 一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据 id 来作为元素的 key
* 当元素没有确定 id 的时候,万不得已你可以使用元素索引 index 作为 key
* 元素的 key 只有放在就近的数组上下文中才有意义。
* 一个好的经验法则是:在 map() 方法中的元素需要设置 key 属性。
* 数组元素中使用的 key 在其兄弟节点之间应该是独一无二的。然而,它们不需要是全局唯一的
*/
// key 会传递信息给 React ,但不会传递给你的组件
/**
* <Post
key={post.id}
id={post.id}
title={post.title} />
Post 组件可以读出 props.id,但是不能读出 props.key。
*/
// 在jsx 中使用 map()
class Number1 extends React.Component {
render() {
return (
<ul>{this.props.items.map(number => <li key = {number.toString()}>{number}</li>)}</ul>
);
}
}
ReactDOM.render(
<Number1 items={arrItem}/>,
document.getElementById('root')
);
// 受控组件
/**
* 在 HTML 中,表单元素(如<input>、 <textarea> 和 <select>)之类的表单元素通常自己维护 state,
* 并根据用户输入进行更新。
* 而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,
* 并且只能通过使用 setState()来更新。
* 我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。
* 渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。
* 被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
*/
class FormComp extends React.Component {
constructor(props) {
super(props);
// select的value在state中,控制默认选中的
this.state = {value: 'apple'};
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>
Name:
<input type= 'text' value= {this.state.value} onChange ={this.handleChange} />
</label>
<div>
水果:
<select value={this.state.value} onChange={this.handleChange} >
<option value='orange' >橘子</option>
<option value='apple' >苹果</option>
<option value='pear' >梨</option>
<option value='mango' >芒果</option>
</select>
</div>
<div>
水果2:
<select multiple={true} value={['apple', 'pear']}>
<option value='orange' >橘子</option>
<option value='apple' >苹果</option>
<option value='pear' >梨</option>
<option value='mango' >芒果</option>
</select>
</div>
<label>
描述:
<textarea type= 'text' value= {this.state.value} onChange ={this.handleChange} />
</label>
<input type ='submit' value= '提交'/>;
</form>
);
}
}
ReactDOM.render(
<FormComp />,
document.getElementById('root')
);
// 处理多个输入
class Inputs extends React.Component {
constructor(props) {
super(props);
this.state = {
value1: true,
value2: 'value2'
};
this.handlechange = this.handlechange.bind(this);
}
handlechange(event) {
const target = event.target;
const name = target.name;
const value = target.type === 'checkbox' ? target.checked : target.value;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<input type='checkbox' name= 'value1' chedked ={this.state.value1} onChange ={this.handlechange}/>
<input type ='text' name = 'value2' value={this.state.value2} onChange ={this.handlechange}></input>
</form>
);
}
}
ReactDOM.render(
<Inputs />,
document.getElementById('root')
);
// 状态提升
function changeFtoC(f) {
return (f - 32) * 5 / 9;
}
function changeCtoF(c) {
return (c * 9 / 5) + 32;
}
function changeTemp(temp, cover) {
const input = parseFloat(temp);
if (Number.isNaN(input)) {
return '';
}
const result = cover(input);
const round = Math.round(result * 1000) / 1000;
return round.toString();
}
const tenpType = {
c: '摄氏',
f: '华氏'
};
class TempF extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.tempChange(e.target.value);
// this.setState({temp: e.target.value});
}
render() {
const temp = this.props.temp;
const scale = this.props.scale;
return (
<fieldset>
<legend>输入{tenpType[scale]} 温度:</legend>
<input type ='text' value = {temp} onChange = {this.handleChange}/>
</fieldset>
);
}
}
class Boilling extends React.Component {
render() {
if (this.props.cTemp > 100) {
return <p> 开水</p>;
}
return <p>没有开水</p>;
}
}
class Temp extends React.Component {
constructor(props) {
super(props);
this.state = {temp: '', scale: 'c'};
this.changeC = this.changeC.bind(this);
this.changeF = this.changeF.bind(this);
}
changeC(temp) {
this.setState({scale: 'c', temp});
}
changeF(temp) {
this.setState({scale: 'f', temp});
}
render() {
const temp = this.state.temp;
const scale = this.state.scale;
const cel = scale === 'f' ? changeTemp(temp, changeFtoC) : temp;
const fah = scale === 'c' ? changeTemp(temp, changeCtoF) : temp;
return (
<div>
<TempF
scale='c'
temp ={cel}
tempChange ={this.changeC} />
<TempF
scale='f'
temp ={fah}
tempChange ={this.changeF} />
<Boilling
cTemp ={parseFloat(cel)}/>
</div>
);
}
}
ReactDOM.render(
<Temp />,
document.getElementById('root')
);
// 组合
/**
* <FancyBorder> JSX 标签中的所有内容都会作为一个 children prop 传递给 FancyBorder 组件。
* 因为 FancyBorder 将 {props.children} 渲染在一个 <div> 中,被传递的这些子组件最终都会出现在输出结果中。
每个组件都可以获取到 props.children。它包含组件的开始标签和结束标签之间的内容
*/
// 需要引入css
class FancyBorder extends React.Component {
render() {
return (
<div className={'FancyBorder FancyBorder-' + this.props.color}>
{this.props.children}
</div>
);
}
}
class Welcome2 extends React.Component {
render() {
return (
<FancyBorder color ='red'>
<h1 className = 'Dialog-title'>Welcome</h1>
<p className ='Dialog-mssage'> Thankn you</p>
</FancyBorder>
);
}
}
ReactDOM.render(
<Welcome2 />,
document.getElementById('root')
);
function Contacts() {
return <div className="Contacts" />;
}
function Chat() {
return <div className="Chat" />;
}
class SplitComp extends React.Component {
render() {
return (
<div className = 'SplitComp'>
<div className = 'SplitComp-left'>
{this.props.left}
</div>
<div className ='SplitComp-right'>
{this.props.right}
</div>
</div>
);
}
}
class SHowSplit extends React.Component {
render() {
return (
<SplitComp
left= {
<Chat />
}
right= {
<Contacts />
} />
);
}
}
ReactDOM.render(
<SHowSplit />,
document.getElementById('root')
);