React笔记-Hooks(九)(非常全面)

React笔记-Hooks(九)

Hooks

概念

React Hooks 的意思是 组件尽量写成纯函数 如果需要外部功能和副作用 就用钩子把外部代码"钩"进来

函数组件和类组件区别

  • 函数组件没有状态(state) 类组件有
  • 函数组件没有生命周期 类组件有(挂载-更新-销毁)
  • 函数组件没有this 类组件有
  • 函数组件更适合做UI展示 类组件更适合做复杂的业务逻辑组件

为什么纯函数组件逐渐取代类组件

React团队希望 组件不要变成复杂的容器 最好只是数据流的管道 开发者根据需要 组合管道即可

Hooks用法

useState() 状态钩子

纯函数组件没有状态,useState()用于设置和使用组件的状态属性

// Hooks是无状态的 所以用这种方式替换类组件中的状态(state)
const [state, setState] = useState(initialValue);
// state:初始的状态属性,指向状态当前值,类似this.state
// setState:修改状态属性值的函数,用来更新状态,小驼峰命名
// setState((currentState) => {]})可以传入一个函数 函数接收一个参数 用于存放当前state
// initialValue:状态的初始值,该值会赋给state

import { useState } from 'react';



function LearnHooks () {

    let a = 1;
    const [num, setNum] = useState(0);
    const [name, setName] = useState([{name : 'bob', age : 18}, {name : 'sam', age : 20}, {name : 'kitty', age : 22}]);

    const addNum = () => {
        setNum(num + 1)
        // setNum是异步操作 所以console.log(num)输出的是更新前的值
        console.log(num)
        a += 1;
        // 这里a永远输出为2
        // 原因是hooks重新渲染是自调用 每次都会重新把a设为1 然后执行 a + 1
        console.log(a)
    }

    console.log('LearnHooks渲染了')
    return (
        <div>
            <h1>学习hooks的userState</h1>
            <div>当前num : {num}</div>
            <button onClick={() => addNum()}>num + 1</button>
            <div>{name.map((item) => {
                    return <div key={item.name}>name : {item.name}, age : {item.age}</div>
                })}
            </div>
            <input type="text" onChange={ ({target : {value}}) => setName([{name : value}])}/>
        </div>
    );
    
}

export default LearnHooks;

useEffect() 副作用钩子

可以实现特定的功能 如异步请求

useEffect(() => {
    // 回调函数,其中是要进行的异步操作代码
    return () => {}
    // useEffect中的return语句可以用于清除effect产生的副作用。当组件卸载时,React会执行return语句中的函数,以清除effect产生的副作用。例如,如果在useEffect中订阅了一个事件,那么在return语句中取消订阅可以避免内存泄漏。
}, [array])
// [array]:useEffect执行的依赖,当该数组的值发生改变时,回调函数中的代码就会被执行
// 如果[array]省略,则表示不依赖,在每次渲染时回调函数都会执行
// 如果[array]是空数组,即useEffect第二项为[],表示只执行一次

import React, { useState, useEffect } from 'react';

function hook() {

  const [num, setNum] = useState(1)
  /**
   * 第一个参数是回调函数
   * 第二个参数是依赖项
   * 每次num变化时都会变化
   * 
   * 注意初始化的时候,也会调用一次
   */
  useEffect(() => {
    console.log("每次num,改变我才会触发")
  }, [num])


  return (
    <div>
      <button onClick={() => setNum(num + 1)}>+1</button>
      <div>你好,react hook{num}</div>
    </div>
  );
}

export default hook;

useLayoutEffect()

useLayoutEffect是React提供的一个Hook,与useEffect功能类似,但在组件更新DOM前执行,而不是之后。

与useEffect不同的是,useLayoutEffect会阻塞浏览器渲染,并立即同步执行副作用函数。这可以确保使用组件的代码看到的是最新的DOM布局,因为它们在组件挂载或更新时都会在渲染通道中优先处理。

// useLayoutEffect接收两个参数:一个副作用函数和一个依赖项数组。副作用函数中可以进行DOM操作、计算布局等任务,并且可以通过返回一个清除函数来清理副作用产生的任何资源。

useLayoutEffect(() => { 副作用函数执行逻辑 }, [ 依赖项 ])

// 1. 编写副作用函数:useLayoutEffect需要传递一个函数作为参数,该函数称为副作用函数。在这个函数里,你可以访问到DOM、执行异步操作或计算等其它操作,并考虑它们的收尾工作。当组件的props或state发生变化时,都将重新运行该函数。
import { useLayoutEffect } from 'react';

function useMyLayoutEffect() {
  // 执行DOM相关操作
  return () => {
    // 清理工作
  };
}


// 2. 将useLayoutEffect挂载到组件:要在组件中使用useLayoutEffect这个函数,只需要调用它即可,并把上一步编写的副作用函数作为第一个参数。

function MyComponent() {

  useLayoutEffect(useMyLayoutEffect, []);

  return <div>Hello, world!</div>;

}


// 给useLayoutEffect传递依赖项数组:和useEffect一样,useLayoutEffect的第二个参数是一个数组,其中包含在副作用函数中需要被“监视”的任何变量。当其中的变量发生更改时,useLayoutEffect将重新运行其副作用函数。

function MyComponent({ name }) {

  useLayoutEffect(() => {

    console.log(`MyComponent is mounted: ${name}`);

  }, [name]);

  return <div>Hello, {name}!</div>;
  
}

useContext() 共享状态钩子

可以共享状态,作用是进行状态的分发,避免了使用Props进行数据的传递

// 第一步:创建全局的Context
const AppContext = React.createContext([初始化参数])

// 第二步:通过全局的Context进行状态值的共享
<AppContext.Provider value={{ 属性名: 值 }}>
    <其他组件1 />
    <其他组件2 />
</AppContext>

// 第三步:使用context
const context = useContext(AppContext);
{context.name}

// 在 App.js 文件中
import React, { createContext, useState } from 'react';
import Child from './Child';

export const MyContext = createContext();

function App() {
  const [count, setCount] = useState(0);

  return (
    <MyContext.Provider value={{ count, setCount }}>
      <div>
        <h1>Count: {count}</h1>
        <button onClick={() => setCount(count + 1)}>Increment</button>
        <Child />
      </div>
    </MyContext.Provider>
  );
}

// 在 Child.js 文件中
import React, { useContext } from 'react';
import { MyContext } from './App';

function Child() {
  const { count, setCount } = useContext(MyContext);

  return (
    <div>
      <h2>Child Component</h2>
      <h3>Count: {count}</h3>
      <button onClick={() => setCount(count - 1)}>Decrement</button>
    </div>
  );
}

useMemo() 记忆钩子(值)

useMemo是React中的一个hook,用于优化组件的性能。它的作用是缓存函数的返回值,只有当依赖项发生变化时才重新计算。这样可以避免在每次渲染时都重新计算函数的返回值,从而提高组件的性能。

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

// 第一个参数是一个回调函数,用于计算需要缓存的值
// 第二个参数是一个数组,用于指定依赖项。只有当依赖项发生变化时,才会重新计算memoizedValue的值。

import React, { useState, useMemo } from 'react';

function MyComponent() {
  const { a, setA } = useState(1);
  const result = useMemo(() => {
    // 只有当a发生变化时才会重新计算。这样可以避免在每次其他渲染时都重新计算结果,提高组件的性能
    return a * 2;
  }, [a]);

  const add = () => {
    setA(a + 1)
  }

  return (
    <div>
      <div>{result}</div>
      <button onClick={() => add()}>a+1</button>
    </div>
  );
}

useCallback() 记忆钩子(函数)

useCallback是React中的一个Hook函数,用于优化函数组件的性能。它的作用是返回一个记忆化的回调函数,当依赖项发生变化时才会重新生成新的回调函数。这样可以避免在每次渲染时都创建新的回调函数,从而提高组件的性能。

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

// 第一个参数是回调函数
// 第二个参数是依赖项数组。当依赖项数组中的任意一个值发生变化时,useCallback会重新生成新的回调函数。如果依赖项数组为空,则每次渲染都会返回同一个回调函数。


// 需要注意的是,useCallback返回的是一个记忆化的回调函数,而不是一个普通的函数。因此,如果需要在组件外部使用该回调函数,需要将其作为props传递给子组件。

// 举例:使用useCallback优化组件性能

import React, { useState, useCallback } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  // 普通的回调函数
  const handleClick = () => {
    setCount(count + 1);
  };

  // 使用useCallback优化的回调函数
  const handleClickMemoized = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>普通的回调函数</button>
      <button onClick={handleClickMemoized}>使用useCallback优化的回调函数</button>
    </div>
  );
}

export default MyComponent;

useReducer() 行为钩子

useReducer是React中一个状态管理的Hooks,用于处理复杂的组件状态逻辑。它和useState类似,都是用于管理组件状态的,但是useReducer可以更好地处理复杂的状态逻辑,尤其是在多个状态相互影响的情况下会更加方便和清晰。


// 1. 定义初始状态(initial state)和reducer函数。reducer函数的作用是根据当前的状态和操作类型(action)来返回新的状态值。

const initialState = {
  count: 0,
};

function reducer(state, action) {
  switch (action.type) {
    case 'ADD':
      return { count: state.count + 1 };
    case 'SUB':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}


// 2. 在组件中使用useReducer Hook,传入reducer函数和initial state参数,获取当前的state值和dispatch函数。

import React, { useReducer } from 'react';

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <h2>Counter: {state.count}</h2>
      <button onClick={() => dispatch({ type: 'ADD' })}>+</button>
      <button onClick={() => dispatch({ type: 'SUB' })}>-</button>
    </div>
  );
}

useRef() 保存引用值

useRef是React中的一个hook,用于创建一个可变的引用,类似于在类组件中使用的this.refs。与useState不同,useRef返回一个可变的值,而不会触发重新渲染组件。

useRef可以用于保存任何可变值,例如DOM元素的引用、定时器的标识符、上一个渲染周期的状态等。它还提供了一个.current属性来访问保存的值。

使用场景

  1. 获取DOM元素的引用

  2. 保存上一个渲染周期的状态

  3. 在useEffect中访问最新的props和state值

  4. 保存定时器的标识符,以便在组件卸载时清除


// useRef创建的ref对象与组件生命周期不相关,因此它不会在调用setState或props更新时自动更新,ref改变取决于使用它的具体方式

const ref = useRef()

// 因为hooks重新渲染其实是组件的自调用,所以我们不能在组件中直接定义一个值,let a = 1 或 const arr = []都是错误的,此时我们使用useRef来保存和访问持久性数据

useImperativeHandle()

useImperativeHandle是React Hook中的一个函数,用于在使用ref时,向父组件暴露子组件的方法或属性。它可以覆盖默认情况下通过ref自动公开该组件实例的方式,从而更加精准的控制哪些内容公开给父组件。

useImperativeHandle接受两个参数:ref对象和一个callback函数。callback函数应该返回包含想要挂载到ref上的任何公共方法或属性的对象。当父组件从ref调用该方法或访问该属性时,callback函数定义的逻辑将被执行。

// 1. 在子组件中使用forwardRef高阶组件转发ref,以在父组件中获得对子组件的引用。

import React, { forwardRef } from 'react';

const Child = forwardRef((props, ref) => {
  // 组件...
});

// 2. 使用useImperativeHandle Hook,将可供父组件访问的方法或属性包装在一个callback函数中,并将该函数作为useImperativeHandle的第二个参数传递

import React, { forwardRef, useImperativeHandle } from 'react';

const Child = forwardRef((props, ref) => {
  const someMethod = () => {
    console.log('Hello from the child component');
  };

  useImperativeHandle(ref, () => ({
    someMethod,
  }));

  return <div>...</div>;
});

export default Child;

// 3. 在父组件中使用ref来调用从子组件暴露的方法

import React, { useRef } from 'react';
import Child from './Child';

function Parent() {
  const childRef = useRef(null);

  const handleClick = () => {
    // 调用子组件中公开的 someMethod 方法
    childRef.current.someMethod();
  };

  return (
    <div>
      <button onClick={handleClick}>调用子组件方法</button>
      <Child ref={childRef} />
    </div>
  );
}

其他

Immutable Data(不可变数据)

解决的问题

在 js 中,对象都是引用类型,在按引用传递数据的场景中,会存在多个变量指向同一个内存地址的情况,如果有多个代码块同时更改这个引用,就会产生竞态

实现的原理

Persistent Data Structure(持久化数据结构):用一种数据结构来保存数据。当数据被修改时,会返回一个对象,但是新的对象会尽可能的利用之前的数据结构而不会对内存造成浪费,也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变,同时为了避免 deepCopy把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享)

redux / flux

// redux / flux 要求采用返回新对象的形式,来触发数据更新、re-render,一般推荐的做法就是采用对象解构的方式。如果 state 对象巨大(注意:对象巨大),在结构、拷贝 state 的过程中,耗时会较长。

return {
  ...state,
  settings: {
    ...state.settings,
    profile:{
      ...state.settings.profile,
      darkmode: true,
    }
  }
}

immer

immer中文网址


// 开源库实现思路:原始对象先做了一层 Proxy 代理,得到 draftState 传递给 function。function(带副作用) 直接更改 draftState,最后 produce 返回新的对象

// 安装
npm install immer

//使用
import React, { useState } from "react";
import produce from "immer";


export default function App() {
  const [list, setList] = useState([1, 2, 3]);

  const addMutable = () => {
    list.push("新数据");
    setList(list);
  };

  const addImmutable = () => {
    /**
     * 第一个参数是要代理的数据
     * 第二个参数是一个函数
     */
    const newVal = produce(list, draft => {
      /**
       * draft 相当于 list
       * 在这个方法里面,可以直接修改draft,注意draft也只能在这个方法里面修改
       * 不需要返回值,immer内部已经帮我处理好了
       */
      draft.push('新数据')
    })
    console.log(newVal)
    setList(newVal);
  };

  return (
    <div className="App">
      <button onClick={addMutable}>已可变的方式添加</button>
      <button onClick={addImmutable}>已不可变的方式添加</button>
      {list.map((item, index) => (<li key={index}>{item}</li>))}
    </div>
  );
}

函数组件传值

hooks直接通过props传值

//父组件中在子组件标签上定义属性
import 子组件
<Son 属性={值}></Son>

// 子组件接收父组件中传递属性
props.属性
父传子

// 父组件
import { useState } from 'react'
import Son from './son'

function Father() {


  const [data, setData] = useState(0)

  return (
    <div>
      <Son
      {/*通过定义属性传值*/}
      name = 'bob' d = {data}
      ></Son>
      <button onClick={() => setData(data + 1)}>+1</button>
    </div>
  )

}

export default Father


// 子组件
import { useState } from 'react'


function Son (props) {

  return (
    <div>
      <div>{props.name}</div>
      <div>{props.d}</div>
    </div>
  )
}



export default Son

子传父

// 父组件
import { useState } from 'react'
import Son from './son'

function Father() {


  const [data, setData] = useState(0)

  const getSon = (msg) => {
    console.log(msg)
  }

  return (
    <div>
      <Son
      {/*定义一个方法用于接收子组件传值*/}
      name = 'bob' d = {data} giveFather={(msg) => getSon(msg)}
      ></Son>
      <button onClick={() => setData(data + 1)}>+1</button>
    </div>
  )

}



export default Father


// 子组件
import { useState } from 'react'


function Son (props) {

  // 接收父组件方法 通过此方法传值给父组件
  const set = () => {
    props.giveFather('儿子给父亲的')
  }


  return (
    <div>
      <div>{props.name}</div>
      <div>{props.d}</div>
      <button onClick={set}>给父亲</button>
    </div>
  )
}



export default Son

React.memo

一个高阶组件,用于优化React组件的性能。它可以帮助我们避免不必要的渲染,从而提高应用程序的性能。当组件的props没有改变时,React.memo会使用之前的渲染结果,而不会重新渲染组件。这对于那些渲染开销较大的组件特别有用。

import React from 'react';

const MyComponent = React.memo(props => {
  // 组件代码
}, (prevProps, currentProps) => {
  
  // prevProps 上次props
  // currentProps 当前props

  return Boolean;
  // false 渲染
  // true 不渲染
});

// 在上面的代码中,我们将一个函数组件传递给React.memo(),并将其返回的新组件赋值给MyComponent。现在,MyComponent将只在其props发生更改时重新渲染。

// 需要注意的是,React.memo()仅检查props的浅层比较。如果props包含复杂的对象或函数,可能需要手动实现更深层次的比较。
import React, { useState } from "react";

// 子组件
const SonMemo = React.memo(
  // 第一个参数 接收一个hook
  (props) => {
    return (
      <div>{props.data}</div>
    )
    // 第二个参数 接收一个函数
  }, (prevProps, currentProps) => {
    // 偶数不渲染
    // 奇数渲染
    return currentProps.data % 2 === 0
  }
)


function FatherMemo () {

  const [num, setNum] = useState(0)

  return (
    <div>
      <h1>{num}</h1>
      {/*点击加一*/}
      <button onClick={() => setNum(num + 1)}>按钮</button>
      <SonMemo data={num}></SonMemo>
    </div>
  )

}


export default FatherMemo;

React hooks中的过期闭包问题

什么是闭包

过期闭包概念

过期闭包(stale closure)是指一个闭包在创建之后,所引用的外部作用域内的变量已经被修改,但闭包内仍然保存了旧值。这就导致闭包中的代码与外部作用域内的实际状态不一致,从而造成错误的结果。

useEffect中过期闭包体现和解决

// react hook中useEffect的过期闭包
import { useEffect, useState } from "react"


function ExpiredClosure () {

  const [num, setNum] = useState(0)

  useEffect(
    () => {
      setInterval(() => {
        // 这里的num在初始化useEffect执行时取到0之后 因为闭包num值不会自动更新
        console.log(num)
      }, 2000)
    }, []
  )

return (
  <div>
    <h1>{num}</h1>
    <button onClick={() => setNum(num + 1)}>+1</button>
  </div>
)

}


export default ExpiredClosure


// 解决react hook中useEffect过期闭包问题
import { useEffect, useState } from "react"


function ExpiredClosure () {

  const [num, setNum] = useState(0)

  useEffect(
    () => {
      const timer = setInterval(() => {
        console.log(num)
      }, 2000)
      return () => {
        // 当组件卸载时 清除计时器
        clearInterval(timer)
      }
      // 添加num为依赖项
    }, [num]
  )

return (
  <div>
    <h1>{num}</h1>
    <button onClick={() => setNum(num + 1)}>+1</button>
  </div>
)

}


export default ExpiredClosure

useState中过期闭包体现和解决

// react hook中useState的过期闭包
import { useState } from "react";


function ExpiredClosure2 () {

  const [num, setNum] = useState(0)


  // 点击正常+1
  const add = () => {
    setNum(num + 1)
  }
  
  // 假设点击时num为3 两秒+2 = 5 在两秒之间不管点击多少次+1操作num变为678910...最后num都为5
  const add2 = () => {
    setTimeout(() => {
      setNum(num + 2)
    }, 2000)
  }

  // 当我们点击+2时候会取得当前值 之后点击其他改变num值 +2中的num都不会随之改变 两秒后取得的num+2给setNum后 渲染页面

  return (
    <div>
      <h1>{num}</h1>
      <button onClick={add}>+1</button><br />
      <button onClick={add2}>+2</button>
    </div>
  )

}


export default ExpiredClosure2;


// 解决react hook中useState过期闭包问题
import { useState } from "react";


function ExpiredClosure2 () {

  const [num, setNum] = useState(0)



  const add = () => {
    setNum(num + 1)
  }

  const add2 = () => {
    setTimeout(() => {
      // setNum中可以传入一个函数 这个函数接收一个参数 用于获取当前num值
      setNum((currentNum) => currentNum + 2)
    }, 2000)
  }

  return (
    <div>
      <h1>{num}</h1>
      <button onClick={add}>+1</button><br />
      <button onClick={add2}>+2</button>
    </div>
  )

}


export default ExpiredClosure2;

本文转载于网络 如有侵权请联系删除

相关文章

  • 以泛在算力挖掘泛在价值——网心科技音视频边缘计算实践

     //  编者按:内容视频化已是当下行业公认的趋势。飞速增长的音视频数据量对计算带来了巨大挑战,而当下云、端算力的局限性,也制约了音视频数据的价值挖掘。本次分享将围绕上述问题,介绍依托5G等基础建设兴起的边缘计算如何为音视频应用松绑,以及网心科技在这一方向上的实践历程。文/曾伟纪整理/LiveVideoStack大家下午好,非常高兴能够再次来到LiveVideoStack和大家进行一个交流。我们借助云端的算力可以让终端得到一个炫酷的体验,这是我认为过去十多年以来技术发展非常重要的一点,今天我的分享也和这个问题有关。首先做个简单的自我介绍,我早年在成立不久的腾讯云做过云端后台的服务,后来在2015-2016年左右,我才开始做现在的这些事情,再后来我才知道,这叫边缘计算,从那时候开始,我和音视频结下了不解之缘,一直持续到今天。所以今天,我想给大家分享“以泛在算力挖掘泛在价值”。1、流失的泛在价值首先,我们来看价值流失的问题。内容视频化是一个大趋势,人是视觉动物,我们对视频的接受程度和我们对视频的喜爱程度是毫无疑问的。无处不在的视频也就代表了无处不在的价值,这也是我们题目中所说的泛在价值。这

  • CSDN博客导出工具 Mac By Swift

    大家好,又见面了,我是全栈君。写这篇文章的主要目的是了解Swift语言本身,如何以及Objc和第三方交互框架必须先用CSDN帐户登录。您可以导出所有的博客文章,加入YAML当首标信息,包括对应标签和分类在头制品信息,和底座式(原版的、转载、翻译)开发环境OSX10.10,Xcode6Beta4。因为Beta4较之前版本号对Swift更新较大,之前版本号编译出报错使用的第三方框架AFNetworkingGTMRegExCategoriesSwift与Cocoa和ObjC交互比較简单,仅仅用Bridging(桥接)一下即可了,详细的做法是使用BridgingHeader文件。这个文件无论是Xcode自己主动生成的还是自己手动加入的都能够,一般这个文件为:ProductName-Bridging-Header.h:在里面直接导入即可:然后找到BuildSettings。搜索Bridging,把Bridging-Header.h文件加入进去就能够了:编译。CSDN下载地址GitHub地址UPDATED:GitHub上已更新至Xcode6Beta6,之前版本号编译会报错。详细看 这里。版权声明:

  • redis 持久化方式 -- AOF & RDB

    1.概述Redis中存储数据的模式有两种:cache-only--只做为“缓存”服务,不持久数据,数据在服务终止后将消失,此模式下也将不存““数据恢复”的手段,是一种安全性低/效率高/容易扩展的persistence--为内存中的数据持久备份到磁盘文件,在服务重启后可以恢复,此模式下数据相对安全对于persistence模式,也就是持久化存储,redis提供了两种持久化方法:RedisDatabase(RDB)Append-onlyfile(AOF)下面,我们就重点介绍一下RDB与AOF的区别2.RDBRDB是默认的redis持久化方式,又称为快照模式(SNAPSHOT)RDB的持久化方式是在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化文件,从而达到持久化数据的作用snapshot过程中并不阻塞客户端请求snapshot首先将数据写入临时文件,当成功结束后,将临时文件重名为dump.rdb每次启动redis时会自动读取dump.rdb完成数据的修复2.1RDB的配置我们可以通过配置文件指定持久化到文件的时间点下面是一个redis配置,由于RDB是默认开启

  • 解构数字化时代平台理念 ——2021年ThoughtWorks技术雷达峰会举行

    2021年5月15日,全球领先的软件及咨询公司思特沃克(ThoughtWorks)在深圳举办了“2021年技术雷达峰会”。本届峰会围绕“数字化时代平台的解构”主题,从组织结构、架构决策、遗留改造、数据赋能等不同角度对数字化时代的平台建设提供了全新视野,为企业构建适合的数字平台战略提供了全新指引。以往对于数字化平台的讨论多针对于业务、架构等,ThoughtWorks在本届技术雷达峰会上,“重新思考”了架构耦合、遗留系统等对数字化平台的解读,更加强调从团队组织的角度理解数字化时代平台。ThoughtWorks中国区CTO徐昊表示:“我们越来越发现组织结构与技术的互补与促进作用远比想象的巨大,特别是在关键技术变革的推动上面,需要结合技术与组织能力。“重新思考”数字化时代的平台解构2021年,后疫情时代新一波数字化浪潮涌起,特别是十四五规划和2035年远景目标纲要中也特别强调“数字化”发展的重要性,加快数字化的发展进程是当代中国经济发展中的重要课题。对于中国企业而言,数字化转型的发展仍然存在着差异性:一方面互联网企业在数字化领域发展迅速,另一方面,很多传统企业还没有做好准备快速实现数字化转型。

  • 2020 , 10 大受欢迎的全球顶级编程语言与薪资水平

    英文|https://codeburst.io/10-top-programming-languages-in-2019-for-developers-a2921798d652翻译|杨小二硬件和软件技术的进步是推动整个互联网技术进步的主要因素。顶尖的编程语言是现代技术与新兴技术的核心组成部分。 今天的开发人员需要学习的编程语言比以往任何时候都要多。同样,许多IT外包公司现在正在使用大量语言来构建所有不同类型的软件应用程序。对于那些利用这些编程语言满足其需求的人(无论是个人还是企业的),都有多种语言可供选择。由于开发时候,需要掌握多种编程语言,因此企业很难在软件开发项目时,找到合适的程序员。而我试图找到一些最有效和最受欢迎的编程语言,供开发人员学习和企业使用。2020年有哪些顶级编程语言受全球欢迎在列出针对开发人员和企业的最佳编程语言之前,我想简要介绍一下其研究工作。因此,这里简要介绍了用于研究的数据:1、收入最高的顶级编程语言(摘自《StackOverflow开发人员调查报告2019》和《Indeed》)。数据来源地址:https://insights.stackoverflow.co

  • 解决Python在导入文件时的FileNotFoundError问题

    例如,在运行这段代码时fromkeras.utilsimportplot_model plot_model(model,to_file=’images/model_mnist.png’,show_shapes=True,show_layer_names=True) 会报错In[8]:FileNotFoundError:[Errno2]Nosuchfileordirectory:‘images/model_mnist.png’ 此时运行的py文件名称为temp.py要导入的文件在temp.py的同级的目录images文件夹下那么应该保证要导入的文件imagesmodel_mnist.png 要跟前面的temp文件在同一目录(不满足,可把imagesmodel_mnist.png移到temp.py同一目录下)或者是提供要导入的文件的完整目录即写作绝对路径如下:fromkeras.utilsimportplot_model plot_model(model,to_file=’C:/Users/MMIS/.spyder-py3/imagesmodel_mnist.png’,show_shape

  • 剑指offer(01-03)题解

    剑指offer01-03题解01题解--二维数组中的查找02题解--替换空格03题解--从头到尾打印链表01题解–二维数组中的查找题目描述在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 思路解析 重点是切记不要把这个数组当成是一直递增的,他只是保证左到右递增,上到下递增,并没有保证整体内部都是递增,举个例子 [1,2,3,4] [2,3,4,5] [3,4,5,6] [4,5,6,7]所以不能想着将它转换成一个数组然后通过二分比较来查找,这里因为里面可能有重复的元素,所以我选择的是讲个数组重新存入一个Hashset之中,这样既能排除掉重复元素,而且能直接调用Hsahset.contains()方法进行验证。 源代码importjava.util.HashSet; publicclassSolution{ publicbooleanFind(inttarget,int[][]array){ booleanflag=false; HashSe

  • python实现贪吃蛇小游戏

    一起来玩游戏?python实现贪吃蛇小游戏先来看看这个小游戏没错这就是强大的python,实现所有不可能。先前,有了解到用人工智能训练贪吃蛇,没错就是snake,可以达到很高的分数,并且损失函数随训练次数的增加,逐渐降低,贪吃蛇能够更准确的吃到食物,简直太神奇了。最近学习了DFS,BFS,这两个搜索图的算法,完全可以用这两个基础算法来实现人工智能的贪吃蛇,A*也可以。算法的主要思路就是通过获取蛇的头部和食物的位置,在避免碰到自己和边缘的前提下进行路径规划。好了就说到这。下面给出这个贪吃蛇的代码,不是AI-snake哦。importsys importos importpygame importrandom importmath pygame.init() pygame.display.set_caption("$nAkebRocolorfUll--FASAL") pygame.font.init() random.seed() #global SPEED=0.36 SNAKE_SIZE=9 APPLE_SIZE=SNAKE_SIZE SEPARATION=10

  • 关于全部已知导致百度索引量下降的原因分析及解决方案

    索引量是流量的基础,索引量数据的每一个变动都拨动着站长敏感的神经,“索引量下降之后该如何着手分析”一直是各位讨论的热门话题。这次站长社区版主老吕又拔刀相助了,看看史上最全的百度索引量下降原因分析及解决方案吧。 一、百度索引下降分析简图 二、导致百度索引量下降的常见原因——网站方原因 1、内容数据所在的网址url未规范统一 自己站点url规范统一 多域名都可以200状态正常访问网页内容;一域名下出现多种url形式可以访问相同内容,如大小写url、url规则变更等。 解决:选择主域名(或主url),其他域名下的所有url都301重定向到主域名(或主url),并站长工具提交域名改版(或目录url改版) 外部平台使用己站数据 A、市场合作,站点数据调用到其他平台上;内容主动外发,推广人员完整转发自有内容到高质量平台——这两个原因都有可能导致搜索引擎收录了外部平台的内容而拒绝了原网站内容 解决:使用站长平台链接提交工具的主动推送功能,及时提交网站新出现的链接,延迟将内容调用到其他平台的时间; B、被镜像,用户通过其他举办主体的域名或url直接可访问己方内容。 解决:关注域名解析安全和服务器安全;

  • 腾讯数据库专家雷海林分享智能运维架构

    2019年5月8日-10日的DTCC2019年中国数据库大会上,腾讯云数据库专家工程师雷海林首受邀做了主题为《TDSQL智能运维平台-扁鹊架构与实践》的技术分享,以下为大会现场演讲实录。雷海林在大会现场关注“腾讯云数据库”官方微信,回复“智能运维”,即可下载本文PPT。一、扁鹊的基本介绍扁鹊系统是TDSQL面向云市场推出的一款针对数据库性能/故障等问题的自动化分析并为用户提供优化/解决方案的产品。1.扁鹊的需求背景TDSQL作为腾讯针对金融场景推出的高一致,分布式数据库集群的解决方案目前已覆盖了腾讯90%的支付业务场景,内部有大量团队使用;同时作为腾讯金融云的数据库产品,支持公有云和专有云两种云解决方案,目前拥有了大量的政府,银行、保险、物流、电商等客户,但随着客户和集群规模的不断扩大,在TDSQL运营过程中也带来了很大的挑战。针对这些问题,我们认为需要一个自动化的故障/性能问题分析系统,减少DBA的重复劳动,沉淀我们的分析经验,快速定位问题,带给我们的客户最快速的响应同时也提升DBA的幸福指数。之所以将这个模块命名为扁鹊,就是希望它能像古代的扁鹊神医为人诊断病因一样也可以为数据库“对

  • P2142 高精度减法

    题目描述高精度减法输入输出格式 输入格式: 两个整数a,b(第二个可能比第一个大) 输出格式: 结果(是负数要输出负号)输入输出样例输入样例#1: 2 1复制输出样例#1: 1复制说明20%数据a,b在longlong范围内100%数据0<a,b<=10的10000次方1#include<iostream> 2#include<cstdio> 3#include<cstring> 4#include<cmath> 5usingnamespacestd; 6constintMAXN=100001; 7chara1[MAXN],b1[MAXN]; 8inta[MAXN],b[MAXN]; 9intans[MAXN]; 10intmain() 11{ 12scanf("%s%s",a1,b1); 13intla=strlen(a1); 14intlb=strlen(b1); 15if(la<lb||(la==lb&&a1[0]<b1[0])) 16{ 17printf("-&

  • Bootstrap快速入门

    Bootstrap学习有两个重点,一个是概念的理解,理解bootstrap是如何通过div来代替过去的table布局的;一个是常用结构的熟悉,做到需要的组件及时能找到,组合一下就可以满足需求。学习后的最大感受就是:bootstrap让前端布局和渲染的工作,由填空题变成了选择题。即便没有很强的审美能力,也可以让网页简洁大方,颜值爆表。 概念BootStrap是由Twitter的两位员工MarkOtto和JacobThornton于2010年8月创建,距今已有7年,不过其仍然是最流行的前端CSS框架。它基于Less前端开发库,提供了常见的CSS和Javascript代码,然开发快速上手。其具有以下特性:完整的基础CSS插件;丰富的预定义样式表;基于jQuery的js插件集;非常灵活的响应式栅格系统,而且崇尚移动先行的思想。随着bootstrap的火爆,出现了很多优秀插件,比如FontAwesome字体。 Bootstrap官网地址,demo和文档非常丰富。 其下载后的源码结构为: 这儿值得的一说的就是fonts中通过字体文件代替了过去的.png,其通过@font-face语法,将安全的W

  • Java线程(三):线程协作-生产者/消费者问题

        上一篇讲述了线程的互斥(同步),但是在很多情况下,仅仅同步是不够的,还需要线程与线程协作(通信),生产者/消费者问题是一个经典的线程同步以及通信的案例。该问题描述了两个共享固定大小缓冲区的线程,即所谓的“生产者”和“消费者”在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者,通常采用线程间通信的方法解决该问题。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。本文讲述了JDK5之前传统线程的通信方式,更高级的通信方式可参见Java线程(九):Condition-线程通信更高效的方式和Java线

  • 如何实现通过Leaflet加载dwg格式的CAD图

    前言 ​ 在前面介绍了通过openlayers加载dwg格式的CAD图并与互联网地图叠加,openlayers功能很全面,但同时也很庞大,入门比较难,适合于大中型项目中。而在中小型项目中,一般用开源的leaflet比较多,leaflet小而美,插件很多。本文介绍如何用Leaflet来加载DWG格式的CAD图,并在上面做应用开发,如与互联网地图叠加显示等。 Leaflet介绍 ​ Leaflet是领先的用于移动友好交互式地图的开源JavaScript库。仅仅重约39KB的JS,它拥有大多数开发者所需要的所有地图功能。Leaflet在设计时考虑到了简单性、性能和可用性。它可以在所有主要的桌面和移动平台上高效地工作,可以通过大量的插件进行扩展,拥有一个漂亮的、易于使用的、记录良好的API,以及一个简单的、可读的源代码。。 Leaflet官网地址https://leafletjs.com/ Leaflet源码地址[https://github.com/Leaflet/ Leaflet中加载CAD栅格瓦片 在leaflet中加载CAD图,需要建立一个由cad建立的坐标系。可以由L.CRS.Si

  • git的安装及使用(三)----SSH连接

     ssh连接和https连接 一、http协议连接远程仓库   注意:这里是找到并删除http的协议用户名密码,因为以后要用ssh协议       二、使用ssh连接远程仓库 1.生成并配置好ssh 1删除了之后,要提交项目至git,又需要用户名密码,那么就需要ssh   git中生成ssh公钥私钥地址:https://gitee.com/help/articles/4181 2生成公钥私钥,把公钥配置到gitee上,以后就不需要输入用户名密码了,走的是ssh 公钥私钥生成步骤: (1)ssh-keygen-trsa-C"306334678@qq.com"#打开gitbash在哪里打开生成都可以,邮箱要改成自己的 (2)会在用户家目录,生成一个.ssh文件夹,非对称加密(公钥和私钥),打开公钥文件夹复制内容到gitee中的公钥中,点确定后输入密码就完成了 (3)在命令行中把https协议改成ssh协议: gitremoteremoveorigin gitremote#此时就没有之前的origin了 gitremoteaddorigingi

  • 移动端开发 干货知识分享

    1、在手机端如果1px线条仍然显示过粗,可以使用css新属性border-image边框图像来解决    例:border-image:url(../img/line-img1.png)20round;    关于border-image熟悉的介绍:http://www.w3cplus.com/content/css3-border-image   2、在部分安卓机上使用border-image后,发现内容区域设置 :active 后不起作用。    原因:border-image后面默认加了fill关键字    解决办法:使用的边框图片,图片中间区域背景一定要是透明的。   3、部分安卓机对键盘事件不兼容,如果是对输入框内容监听变化可用input事件   4、部分iphone上,页面内如果有position:fixed固定内容,第一次滑动页面时,固定内容会随页面滑动,松开手后,内容回到原位。bug原因和覆盖范围未知。

  • jmeter Address already in use: connect 解决方案

    背景: 最近压测接口时,并发一段时间后,会报java.net.BindException:Addressalreadyinuse:connect       原因: Jmeter里的httpsample勾选了keepalive,导致会话一直保持,而windows本身的端口有限,导致端口被占用完后,无法分配新的端口,因此会产生java.net.BindException:Addressalreadyinuse:connect报错。       解决方案: HTTPSAMPLE不勾选keepalive     ————————————————版权声明:本文为CSDN博主「「已注销」」的原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qic1993/article/details/106208061

  • NOIP退役记

    10.10 想着自己再过一个月就要退役了,真叫人心酸。想到徐志摩的诗: “悄悄地,我走了,正如我悄悄的来,我挥一挥衣袖,不带走一片云彩。” 学了这么久的OI,感觉真的就像诗里讲的一样,有一天自己也会离开,不带走一片云彩地离开。有时,看着自己每况愈下的成绩,看着旁边不管是学科还是竞赛的强手们一天一天脚踏实的扎扎实实的努力,我真的会怀疑当初自己的决定是不是足够成熟,足够睿智。 “写下不忘初心四个字的时候,我的手甚至在颤抖。” 也许我的累只是假象,也许我真的只是不够努力,或许还是我太笨,思路清奇的题目的一道接着一道,消磨意志的考试一场连着一场。每一天过着抱火卧薪,来之坎坎的日子。这是一年前的自己未曾预料到的。 “我就要来长郡,来长郡搞竞赛。”“我来长郡就是搞竞赛的。”那个时候自命不凡气势汹汹,总觉得可以成就一番。听人说,那个时候的自己也挺让人怀念的。这一年来变了好多好多,感觉自己长大了好多好多。其实感觉起来,长大也不是什么好事。破茧成蝶的故事是真是假,蝴蝶是否真的快乐没有人知道,也没有人在意。 弗洛伊德曾经说过:梦是人最真实的内心世界。 在我写下这些也许只有自己能懂的文字的时候,我知道这个机

  • 牛客挑战赛59

    木桩: 链接:https://ac.nowcoder.com/acm/contest/11199/A 分析:首先考虑一个小木桩前有x个大木桩后有y个大木桩 则这个小木桩的贡献就是x×y-x很明显均值不等式得到x和y尽量均分才能答案最大 如果a为偶数那么恰好前后各一半 如果a为奇数那么多的那一个放在后面一定最优 code: #include<bits/stdc++.h> usingnamespacestd; #definelowbit(x)x&(-x) #definelllonglong intT; voidsolve(); intmain(){ cin>>T; while(T--)solve(); return0; } voidsolve(){ lla,b; scanf("%lld%lld",&a,&b); llt1=a/2; llt2=t1; if(a%2)t2++; cout<<b*(t2-1)*t1<<endl; } 复制 游戏: 链接:https://ac.nowcoder.com/acm/

  • 【Maven】如何构建maven项目;maven 核心知识

    maven思维导图:  ps:资料出处---动力节点资料广场   笔记第一部分: 1、传统开发项目的问题(没有使用maven管理的项目): 1)很多模块之间有关系,手工管理关系,比较繁琐。 2)需要很多第三方功能,需要很多jar文件,需要手工从网络中获取各个jar文件。 3)需要管理jar的版本,需要的是mysql.5.1.5.jar,那就不能随便找一个mysql版本。 4)管理jar文件之间的依赖,你的项目要使用a.jar,而a.jar需要使用b.jar里面的类。所以必须首先获取到b.jar才可以使用a.jar。    a.jar需要b.jar这个关系叫做依赖,或者你的项目中要使用mysql的驱动,也可以叫做项目依赖mysql驱动   2、maven管理项目的优点: 1)maven可以帮助管理jar文件,管理你需要的jar版本。 2)自动下载jar和它的文档,源代码。 3)管理jar之间的依赖,a.jar需要b.jar,maven会自动下载b.jar。 4)帮你编译程序,把java编译为class。 5)帮你测试你的代

  • React-Native学习系列(二) Image和ScrollView

    接下来,我们接着(一)继续讲,今天我们学习的是Image组件和ScrollView组件。 Image组件 Image:一个用于显示多种不同类型图片的React组件。那么要如何使用呢? 引入本地图片: <Imagesource={require('../images/myHeader.png')}/> 复制 引入网络图片 <Imagestyle={styles.imageStyle}source={{uri:'https://facebook.github.io/react/img/logo_og.png'}}/> 复制 这里要说的是加载网络图片的话,必须指定图片大小,例如logo_og.png,否则会遇到无法显示的问题,而引入本地图片的话,如果不指定图片的大小,那么默认的是图片的原大小,例如myHeader这张图片,大小为250*250,默认显示的是250*250. 安卓和iOS的图片尺寸不一样,那么给图片命名为my-icon.android.png/my-icon.ios.png,系统会自动判断系统来加载图片. 那么现在咱们来说一下Image的属性 widt

相关推荐

推荐阅读