react - high
- fragment
01
<script type="text/babel">
class Table extends React.Component {
render() {
return (
<table>
<tr>
<td>你好</td>
<td>世界</td>
</tr>
</table>
)
}
}
ReactDOM.render(<Table />, document.getElementById("app"));
</script>
02
<script type="text/babel">
class Table extends React.Component {
render() {
return (
<table>
<tr>
<Coloumn />
</tr>
</table>
)
}
}
function Coloumn () {
return (
<div>
<td>你好</td>
<td>世界</td>
</div>
)
}
ReactDOM.render(<Table />, document.getElementById("app"));
</script>
出现以上问题是因为:tr 中应该放 td ,不应该是 div
那么该如何解决呢?
03 Fragment 给子元素分组,不需要向子元素添加额外的DOM节点
<script type="text/babel">
class Table extends React.Component {
render() {
return (
<table>
<tr>
<Coloumn />
</tr>
</table>
)
}
}
// 写法一
// function Coloumn () {
// return (
// <React.Fragment>
// <td>你好</td>
// <td>世界</td>
// </React.Fragment>
// )
// }
// 写法二:短语法
function Coloumn () {
return (
<>
<td>你好</td>
<td>世界</td>
</>
)
}
ReactDOM.render(<Table />, document.getElementById("app"));
</script>
04 注意:短语法不支持key
Fragment方式
<script type="text/babel">
const posts = [
{id:1,title:'a',contect:'a-content'},
{id:2,title:'b',contect:'b-content'},
{id:3,title:'c',contect:'c-content'}
]
function Blogs(props) {
const {posts} = props
return (
<dl>
{
posts.map(item=>(
<React.Fragment key={item.id}>
<dt>{item.title}</dt>
<dd>{item.contect}</dd>
</React.Fragment>
))
}
</dl>
)
}
ReactDOM.render(<Blogs posts={posts}/>, document.getElementById("app"));
</script>
短语法方式
- errorboundary
01 案例:点击到5时,抛出问题 – throw
<script type="text/babel">
class BugCount extends React.Component {
state = { count: 0 }
handleClick = () => {
this.setState(({ count }) => {
return { count: count + 1 }
})
}
render() {
if(this.state.count === 5) {
throw new Error('count error')
}
return <h1 onClick={this.handleClick}>{this.state.count}</h1>
}
}
ReactDOM.render(<BugCount />, document.getElementById("app"));
</script>
- 使用 throw 页面直接挂掉,用户体验不好
02 案例:点击到5时,抛出问题 – ErrorBoudary
- 需求:程序错误 不应该导致应用崩溃
- 作业:错误编辑本身是一个组件,能捕获子组件的错误,但是无法捕获自身错误
- 渲染:如果子组件出现错误,则渲染错误边界自定义的错误页面,而不是直接渲染错误或空白
- 思路:声明错误状态 - 捕获子组件错误 - 错误同步到state
-> 有错误:渲染自定义的错误页面
-> 没错误:渲染子组件
<script type="text/babel">
class BugCount extends React.Component {
state = { count: 0 }
handleClick = () => {
this.setState(({ count }) => {
return { count: count + 1 }
})
}
render() {
if (this.state.count === 5) {
throw new Error('count error')
}
return <h1 onClick={this.handleClick}>{this.state.count}</h1>
}
}
class ErrorBoudary extends React.Component {
// 01 错误容器
state = { error: null, errorInfo: null }
// 02 钩子函数:子组件发生错误异常 会被错误边界捕获 (react自动执行componentDidCatch,并传入错误信息)
componentDidCatch(error, errorInfo) {
console.log('----componentDidCatch');
// 03 同步
this.setState({
error,
errorInfo
})
console.log(error);
console.log(errorInfo);
}
render() {
const { error, errorInfo } = this.state
// 04 页面渲染
// 有错误
if (error || errorInfo) {
return (
<div>
<h2>Something go wrong</h2>
<details style={{whiteSpace:'pre-wrap'}}>
{error && error.toString()}
<br />
{errorInfo && errorInfo.toString()}
</details>
</div>
)
}
// 没错误
return this.props.children
}
}
function App() {
return (
<div>
<h1>App</h1>
<ErrorBoudary>
<BugCount />
</ErrorBoudary>
</div>
)
}
ReactDOM.render(<App />, document.getElementById("app"));
</script>
// 错误边界包裹 多个子组件,有一个组件出现问题,错误边界自定义的错误页面 会覆盖所有子组件
function App() {
return (
<div>
<h1>App</h1>
<ErrorBoudary>
<BugCount />
<BugCount />
<BugCount />
</ErrorBoudary>
</div>
)
}
// 错误边界 各自独立包裹子组件 : 互相不影响 各自提示独立的错误信息
function App() {
return (
<div>
<h1>App</h1>
<ErrorBoudary >
<BugCount />
</ErrorBoudary>
<ErrorBoudary >
<BugCount />
</ErrorBoudary>
<ErrorBoudary >
<BugCount />
</ErrorBoudary>
</div>
)
}
- A higher-order component (HOC) 高阶组件 一种模式 / 高级技术
- 作用 : 对现有的组件的增强
- 场景 :
代码复用 : 将多个组件的公共代码抽离出来
使用三方组件 : 保护三方组件 =>原有组件 不受侵害
01
<script type="text/babel">
class A extends React.Component {
common() {
return 'common function logic'
}
render() {
return (
<div>
<h1>A component</h1>
{
this.common()
}
</div>
)
}
}
class B extends React.Component {
common() {
return 'common function logic'
}
render() {
return (
<div>
<h1>B component</h1>
{
this.common()
}
</div>
)
}
}
class App extends React.Component {
render() {
return (
<div>
<h1>App component</h1>
<A></A>
<B></B>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById("app"));
</script>
02
<script type="text/babel">
// 参数 首字母大写 : 组件; 返回值 也应该是一个组件
let HOC = (Component) => {
return class _ extends React.Component {
// 增强 : 封装公共逻辑
common = () => {
return "commmon function logic";
};
render() {
// 将增强内容 通过props 注入到每个组件里面
return <Component common={this.common} />;
}
};
};
class A extends React.Component {
render() {
return (
<div>
<h1>A component</h1>
{this.props.common()}
</div>
);
}
}
class B extends React.Component {
render() {
return (
<div>
<h1>B component</h1>
{this.props.common()}
</div>
);
}
}
let HocA = HOC(A)
let HocB = HOC(B)
class App extends React.Component {
render() {
return (
<div>
<h1>App component</h1>
<HocA></HocA>
<HocB></HocB>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
</script>
- ajax
01 axios _ 案例:获取star最多的仓库
<script type="text/babel">
class App extends React.Component {
state = {
repoName: '',
repoUrl: '',
}
render() {
const { repoName, repoUrl } = this.state
return (
<div>
<h1>most stars repo is <a href={repoUrl}>{repoName}</a></h1>
</div>
)
}
componentDidMount() {
const {url} = this.props
// 不推荐使用:ajax - promise ajax(用ajax封装promise)
// fetch
// axios
axios.get(url)
.then(response=>{
let result = response.data
console.log(result);
// 获取star最多的仓库
let repo = result.items[0]
console.log(repo);
let {name,html_url} = repo
this.setState({
repoName: name,
repoUrl: html_url
})
})
}
}
const url = 'https://api.github.com/search/repositories?q=reac&sort=stars'
ReactDOM.render(<App url={url}/>, document.getElementById("app"));
</script>
02 axios _ 案例
<script type="text/babel">
class App extends React.Component {
state = {
repoName: '',
repoUrl: '',
repos: []
}
render() {
const { repoName, repoUrl, repos } = this.state
return (
<div>
<h1>most stars repo is <a href={repoUrl}>{repoName}</a></h1>
<ul>
{
repos.map(repo=>{
return <li key={repo.id}><a href={repo.html_url}>{repo.name}</a></li>
})
}
</ul>
</div>
)
}
componentDidMount() {
const { url } = this.props
axios.get(url)
.then(response => {
let result = response.data
console.log(result);
let repos = result.items
this.setState({
repos
})
})
}
}
const url = 'https://api.github.com/search/repositories?q=vue&sort=stars'
ReactDOM.render(<App url={url} />, document.getElementById("app"));
</script>
03 fetch _ 案例
<script type="text/babel">
class App extends React.Component {
state = {
repoName: '',
repoUrl: '',
repos: []
}
render() {
const { repoName, repoUrl, repos } = this.state
return (
<div>
<h1>most stars repo is <a href={repoUrl}>{repoName}</a></h1>
<ul>
{
repos.map(repo => {
return <li key={repo.id}><a href={repo.html_url}>{repo.name}</a></li>
})
}
</ul>
</div>
)
}
componentDidMount() {
const { url } = this.props
fetch(url, { method: 'GET' })
.then(response => response.json())
.then(
data => {
console.log(data);
// 获取star最多的仓库
let repo = data.items[0]
console.log(repo);
let { name, html_url } = repo
this.setState({
repoName: name,
repoUrl: html_url
})
}
)
}
}
const url = 'https://api.github.com/search/repositories?q=reac&sort=stars'
ReactDOM.render(<App url={url} />, document.getElementById("app"));
</script>