1.React组件一般k提供方法f而是某种状态机
2.React组件可以理解q一o纯函数
3.单向数据绑定
jsx:在js代码中直接写HTML标记,其本质:动态创建组建的语法糖React.createElement
。
const e=<h1>eee</h1>;
3. 在属性中使用表达式
<View foo={1+2+3} />;
5. 扩展属性
const obj={a:'222',c:1111}
const e=<View {...obj} />;
6. 表达式作为子元素
const e=<h1>{props.msg}</h1>;
1.React 认q小写的 tag 是原生 DOM 节点,如 div
2.大写字母开头为自定义组件
3.JSX标记可以直接使用属性语法,例如
如何工作的,没有进行优化前的复杂度是:O(n^3)
高阶组件接受组件作为参数,返回新的组件。
// value 是 上面传过来的name;children是 返回的整个函数
{this.props.value && this.props.children(this.props.value)}
函数作为子组件的设计模式
React.createContext
创建一个新的contextconst LocaleContext = React.createContext(enStrings);
Provider
组件 <LocaleContext.Provider value={this.state.locale}>
<button onClick={this.toggleLocale}>
切换语言
</button>
{this.props.children}
</LocaleContext.Provider>
Provider
组件下,使用Consumer
组件;否则的话Consumer
组件 就使用的默认初始值<LocaleContext.Consumer>
{locale => (
<div>
<button>{locale.cancel}</button>
<button>{locale.submit}</button>
</div>
)}
</LocaleContext.Consumer>
以下是全部代码
import React from "react";
const enStrings = {
submit: "Submit",
cancel: "Cancel"
};
const cnStrings = {
submit: "提交",
cancel: "取消"
};
const LocaleContext = React.createContext(enStrings);
class LocaleProvider extends React.Component {
state = { locale: cnStrings };
toggleLocale = () => {
const locale =
this.state.locale === enStrings
? cnStrings
: enStrings;
this.setState({ locale });
};
render() {
return (
<LocaleContext.Provider value={this.state.locale}>
<button onClick={this.toggleLocale}>
切换语言
</button>
{this.props.children}
</LocaleContext.Provider>
);
}
}
class LocaledButtons extends React.Component {
render() {
return (
<LocaleContext.Consumer>
{locale => (
<div>
<button>{locale.cancel}</button>
<button>{locale.submit}</button>
</div>
)}
</LocaleContext.Consumer>
);
}
}
export default () => (
<div>
<LocaleProvider>
<div>
<br />
<LocaledButtons />
</div>
</LocaleProvider>
<LocaledButtons />
</div>
);
这里多了一个Middlewares中间件,这里举个例子,使用redux-thunk
;它接收到actions的时候,不是直接访问dispatch,而是去访问api,如果请求的api返回的是一个成功,他就会返回一个成功的action,失败的话 就会返回一个失败的action。也就是Middlewares进行先截获,预处理,再返回新的action。异步action是几个同步action的使用,通过中间件进行实现的。
Home
BrowserRouter
HashRouter
MemoryRouter
(浏览器URL不发生变化,路由存放到内存中)1.: 普通链接,不会触发浏览器刷新
2.:类似 Link 但是会添加当前选中状态
3. :满足条件时提示用户是否离开当前页面
4.: 重定向当前页面,例如登录判断
5. : 路由配置的核心标记f路径匹配时显示对应组件
6. :只显示第一个匹配的路由
this.props.match.params
简单介绍
使用 next.js
开发。
https://www.nextjs.cn/
1.Jest:Facebook开源的 js单元测试框架
2.JS DOM 浏览器环境的 NodeJS 模拟
3.Enzyme:React 组件渲染和测试
4.nock模拟 http 请求
8. sinon: 函数模拟和调用跟踪
6.istanbul:单元测试覆盖率
前端项目的理想架构:
可维护,可扩展,可测试,易开发,易构建
易于开发
易于扩展
易于维护
1.代码是否容易理解
3. 文档是否健全
易于测试
4. 功能的分层是否清晰
5. 副作用少
6. 尽量使用纯函数
易于构建
7. 使用通用技术和架构
8. 构建工具的选择
index.js
内的数据;1.请求之间无依赖 关系,可以并发进行
2.请求有依赖 需要依次进行
3.请求完成之前,页面显示 Loading 状态
1.使用 URL 进行导航的好处
2.表单内容存放的位置
3.页面状态如何切换
1.写弹窗使用的api
2.可以将虚拟 DOM 映射到任何真实 DOM 节点
3.解决了漂浮层的问题,比如Dialog,Tooltip 等
renderDialog() {
return (
<div className="portal-sample">
<div>这是一个对话框!</div>
<br />
<Button
type="primary"
onClick={() => this.setState({ visible: false })}
>
关闭对话框
</Button>
</div>
);
}
render() {
if (!this.state.visible) return this.renderButton();
return ReactDOM.createPortal(
this.renderDialog(),
document.getElementById("dialog-container"),
);
}
}
import React, { Component } from "react";
require("./DndSample.css");
const list = [];
for (let i = 0; i < 10; i++) {
list.push(`Item ${i + 1}`);
}
const move = (arr, startIndex, toIndex) => {
arr = arr.slice();
arr.splice(toIndex, 0, arr.splice(startIndex, 1)[0]);
return arr;
};
const lineHeight = 42;
class DndSample extends Component {
constructor(props) {
super(props);
this.state.list = list;
}
state = {
dragging: false,
draggingIndex: -1,
startPageY: 0,
offsetPageY: 0,
};
handleMounseDown = (evt, index) => {
this.setState({
dragging: true,
startPageY: evt.pageY,
currentPageY: evt.pageY,
draggingIndex: index,
});
};
handleMouseUp = () => {
this.setState({ dragging: false, startPageY: 0, draggingIndex: -1 });
};
handleMouseMove = evt => {
let offset = evt.pageY - this.state.startPageY;
const draggingIndex = this.state.draggingIndex;
if (offset > lineHeight && draggingIndex < this.state.list.length - 1) {
// move down
offset -= lineHeight;
this.setState({
list: move(this.state.list, draggingIndex, draggingIndex + 1),
draggingIndex: draggingIndex + 1,
startPageY: this.state.startPageY + lineHeight,
});
} else if (offset < -lineHeight && draggingIndex > 0) {
// move up
offset += lineHeight;
this.setState({
list: move(this.state.list, draggingIndex, draggingIndex - 1),
draggingIndex: draggingIndex - 1,
startPageY: this.state.startPageY - lineHeight,
});
}
this.setState({ offsetPageY: offset });
};
getDraggingStyle(index) {
if (index !== this.state.draggingIndex) return {};
return {
backgroundColor: "#eee",
transform: `translate(10px, ${this.state.offsetPageY}px)`,
opacity: 0.5,
};
}
render() {
return (
<div className="dnd-sample">
<ul>
{this.state.list.map((text, i) => (
<li
key={text}
onMouseDown={evt => this.handleMounseDown(evt, i)}
style={this.getDraggingStyle(i)}
>
{text}
</li>
))}
</ul>
{this.state.dragging && (
<div
className="dnd-sample-mask"
onMouseMove={this.handleMouseMove}
onMouseUp={this.handleMouseUp}
/>
)}
</div>
);
}
}
export default DndSample;
//css
.dnd-sample ul {
display: inline-block;
margin: 0;
padding: 0;
background-color: #eee;
}
.dnd-sample li {
cursor: default;
list-style: none;
border-bottom: 1px solid #ddd;
padding: 10px;
margin: 0;
width: 300px;
background-color: #fff;
}
.dnd-sample-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0);
}