当前位置: 首页 > 软件库 > 程序开发 > >

hooked-components

授权协议 MIT License
开发语言 JavaScript
所属分类 程序开发
软件类型 开源软件
地区 不详
投 递 者 傅高逸
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

hooks-component

Addon used to experiment with React Hooks style APIs in Ember apps viaexisting public APIs.

Installation

ember install hooks-component

This addon provide 2 DIFFERENT - API's

  • React way hooks implementation (always call component function on rerender).
  • Ember way hooks implementation (call component function on first render only).

Usage in React-Way

The hooks-component API supports public React HooksAPI

Builtin hooks

  • useEffect -> just like in React API
  • useState -> just like in React API
  • useLayoutEffect -> just like in React API

  • getService -> getService(serviceName) -> service lookup hook
  • getController -> getController(serviceName) -> controller lookup hook
  • getRoute -> getRoute(routeName) -> route lookup hook
  • getStore -> store service lookup
  • getOwner -> getOwner() -> equals getOwner(this) in Ember.

Example

import { reactComponent, useEffect, useState } from "hooks-component";

function ConferenceSpeakersReact() {
	const [ speakers ] = useState(['Tom', 'Yehuda', 'Ed']);
	const [ current, updateCurrent ] = useState(0);

	useEffect(() => {
		console.log('dummy effect');
	});

	const next = () => {
		let nextSpeaker = current + 1;
		updateCurrent(nextSpeaker);
	}

	return {
		currentlySpeaking: speakers[current],
		moreSpeakers: (speakers.length - 1) > current,
		current,
		next, speakers
	}
}

export default reactComponent(ConferenceSpeakersReact);
{{!-- app/templates/components/conference-speakers-react.hbs --}}

<div>
  <p>Speaking: {{this.currentlySpeaking}}</p>
  <ul>
    {{#each speakers key="@index" as |speaker|}}
      <li>{{speaker}}</li>
    {{/each}}
  </ul>

  {{#if this.moreSpeakers}}
    <button onclick={{action this.next this.current}}>Next</button>
  {{else}}
    <p>All finished!</p>
  {{/if}}
</div>

How to create custom hooks?

  • getContextId -> getContextId() -> get current instance context id (same between rerenders)
  • getRerender -> return binded to current instance update function
  • addBeforeCallTask -> execute some callback before component update
  • addBeforeDestroyTask -> execute some callback before any component destroy
// utils/custom-hook.js

import { getContextId, getRerender, addBeforeCallTask, addBeforeDestroyTask } from  "hooks-component";

const DUMMY_STORE = {};
var CALL_COUNTER = 0;

addBeforeCallTask(()=>{
	CALL_COUNTER = 0;
});

addBeforeDestroyTask(()=>{
	const uid = getContextId();
	if (uid in DUMMY_STORE) {
		delete DUMMY_STORE[uid];
	}
});

export function myCustomHook(componentStoreDefaultValue = {}) {
	const uid = getContextId(); // current component instance ID
	const hookCallId = CALL_COUNTER; // how many times hook called during rendering
	if (!(uid in DUMMY_STORE)) {
		DUMMY_STORE[uid] =  {}; // init store for component instance;
	}
	if (!(hookCallId in DUMMY_STORE[uid])) {
		// init store for exact call number inside component isntance;
		DUMMY_STORE[uid][hookCallId] = componentStoreDefaultValue;
	}
	// get current instance + callNumber state
	let state = DUMMY_STORE[uid][hookCallId];
	// get rerender function (must be inside hook)
	let rerender = getRerender();
	// increment hook call counter
	CALL_COUNTER++;
	// return current state for exact component and callNumber and update state function
	return [ state, function(newState) {
		Object.assign(state, newState);
		// rerender will invoke component rerender
		rerender();
	}
}
import { reactComponent } from "hooks-component";
import myCustomHook from "utils/custom-hook";

function ConferenceSpeakersReact() {
	const [ state , patchState ] = myCustomHook({ keys: 1 });
	const [ fish, patchFish ] = myCustomHook({ salmon: 1 });
	const { keys } = state;
	const { salmon } = fish;

	const next = () => {
		patchState({
			keys: keys + 1
		})
	}

	const addSalmon = () => {
		patchFish({
			salmon: salmon + 1
		})
	}

	return { keys, next, salmon }
}

export default reactComponent(ConferenceSpeakersReact);

Usage in Ember-Way

The hooks-component API supports part of React hooks API, including:

updateContext - just like setProperties;
useEffect - do some calculation after dependent keys changed
extract - just like getWithDefault for component arguments

useEffect - inside component function context support: function, tracked property paths in array-like style ['foo.length', 'foo', 'foo.firstObject'];

All effects called during first render, on rerender effects called only if "tracked" property changed.

Example

// app/components/conference-speakers.js (.ts would also work)
import hookedComponent from "hooks-component";

function ConferenceSpeakers(attrs = {}) {

	const { updateContext, useEffect, extract } = this;

	useEffect(({current, speakers}) => {
		updateContext({
			currentlySpeaking: speakers[current],
			moreSpeakers: (speakers.length - 1) > current
		})
	}, ['current'] );

	const next = (current) => {
		current++;
		updateContext({
			current 
		});
	}

	return extract(attrs, {
		next,
		current: 0,
		speakers: ['Tom', 'Yehuda', 'Ed']
	});
}

export default hookedComponent(ConferenceSpeakers);
{{!-- app/templates/components/conference-speakers.hbs --}}

<div>
  <p>Speaking: {{currentlySpeaking}}</p>
  <ul>
    {{#each speakers key="@index" as |speaker|}}
      <li>{{speaker}}</li>
    {{/each}}
  </ul>

  {{#if moreSpeakers}}
    <button onclick={{action next this.current}}>Next</button>
  {{else}}
    <p>All finished!</p>
  {{/if}}
</div>

useEffect API

function shouldRecomputeEffect(oldObject: object, newObject: object): boolean;
type Tracker = string | object | shouldRecomputeEffect;
type cleanupComputedEffect = undefined | Function;
function computeEffect(newContext: any): cleanupComputedEffect;

function useEffect(computeEffect, trakedItems?: Tracker | Tracker[] , useTrackersOnFirstRender?: boolean = false)

How it's working?

Current hookedComponents implementation logic:

  • We run component function only once, in component creation time.
  • component function accept named params (args) as first argument, and return context object.
  • updateContext method invoke existing effects and then, do setProperties(currentContext, updatedProps).
  • if component args updated, it invokes updateContext method with updated args.
  • useEffect method adds "after updateContext and before setProperties callbacks with updatedProps object as argument";
  • if useEffect call return function, it will be called before this effect call next time.
  • updateContext inside useEffect don't reinvoke effects, just patching updatedProps with new data.

Contributing

Installation

  • git clone <repository-url>
  • cd hooks-component
  • yarn install

Linting

  • yarn lint:js
  • yarn lint:js --fix

Running tests

  • ember test – Runs the test suite on the current Ember version
  • ember test --server – Runs the test suite in "watch mode"
  • ember try:each – Runs the test suite against multiple Ember versions

Running the dummy application

For more information on using ember-cli, visit https://ember-cli.com/.

License

This project is licensed under the MIT License.

 相关资料
  • 问题内容: 我有一个要在组件扫描时排除的类。我正在使用下面的代码来做到这一点,但这似乎没有用,尽管一切似乎都正确 实际上,我想在我的其余api逻辑中使用实现“ Service”接口的“ ServiceImpl”类,并在进行api的集成测试时希望排除这种实现并加载模拟的实现。但这似乎没有发生,即使使用上面的内容我也收到以下错误 我花了太多时间在此上,但没有任何效果。 任何帮助表示赞赏。 问题答案:

  • 问题内容: 我正在使用Spring 3.1,并使用和属性引导应用程序。 实际的开始是 该配置类带有注释 而且效果很好。但是,我想更详细地说明我扫描的软件包,所以我尝试了。 但是,此操作失败,并显示错误消息,提示我找不到使用注释指定的组件。 做我追求的正确方法是什么? 谢谢 问题答案: @ComponentScan使用字符串数组,如下所示: 当您仅在一个字符串中提供多个包名称时,Spring会将其解

  • 问题内容: 我有一个要从特定对象中排除的组件: 否则,它似乎与我项目中的其他班级发生冲突。我不完全理解碰撞,但是如果注释掉注释,事情就会像我希望的那样工作。但是其他依赖于此库的项目希望此类由Spring管理,因此我只想在我的项目中跳过它。 我尝试使用: 但它似乎不起作用。如果尝试使用,则会收到一个奇怪的错误,提示你无法加载一些看似随机的类: 原因:java.io.FileNotFoundExcep

  • 问题内容: 我想在Spring中从基于XML的配置切换为基于Java的配置。现在,我们的应用程序上下文中具有以下内容: 但是如果我写这样的话… …它将从这两个软件包中排除服务。我有一种强烈的感觉,我正在尴尬地忽略一些琐碎的事情,但是找不到解决方案来将过滤器的范围限制为。 问题答案: 你只需要为所需的两个注释创建两个类。 因此,例如,你的包装将有一个类: 然后是你的包裹的二等舱: 然后在实例化Spr

  • 问题内容: 我知道它的菜鸟问题,我真的在询问之前四处搜寻。但是我想知道的事情并没有确切的答案。我们如何不使用目标C将字符串拆分为数组?例如: 我知道它不起作用,但是我正在寻找那样的东西。我想用“”分割字符串(或其他字符/字符串) 想法:对我来说可能很好,扩展了字符串类。但是我不知道我该怎么做。 编辑:忘记导入基础。如果我导入基础,它将起作用。但是与扩展String类有什么关系吗?谢谢 问题答案:

  • 我正在使用令人敬畏的“样式化组件” 但我现在使用的是另一个包,它将一个元素封装在其中,所以我不能将我的StyledComponents推到那里,因为我不想更改他的包。 我看到《魅力》有一个很好的把戏。StyledComponents支持这一点吗? 如果你想知道我为什么需要它,这里有一个例子:这是我正在使用的一个外部包: 所以你可以看到我需要传递一个json风格或类Name 所以魅力在这里会起作用,