苗条-通过常规道具传递使用上下文API(setContext / getContext)

时间:2020-04-23 12:54:52

标签: javascript svelte

这是一个简单的例子:

    TestSample.java
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
@WebServlet("/MSTeamsServlet/api/messages")
public class TestSample extends HttpServlet {
    private static final long serialVersionUID = 1L;
    public TestSample() {
        super();
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().append("Served at: ").append(request.getContextPath());
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletInputStream st = request.getInputStream();
        JSONObject inputjson = new JSONObject();
        JSONParser parser = new JSONParser();
        String inputJson ="";
        try {
            BufferedInputStream bin = new BufferedInputStream(st);
            int ch;
            inputJson= "";
            while ((ch = bin.read()) != -1) {
                inputJson = inputJson+(char)ch;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        String result = "";
        System.out.println("INSIDE MS TEAMS SERVLET:::");
        System.out.println("REQUEST:"+inputJson);
        JSONObject json = new JSONObject();
        JSONParser parse = new JSONParser();
        JSONObject requestBody = new JSONObject();
        TestRequest client = new TestRequest();
        try
        {
            requestBody = (JSONObject)parse.parse(inputJson);
            JSONObject conversation = (JSONObject) requestBody.get("conversation");
            String id = requestBody.get("id").toString();
            String serviceUrl = requestBody.get("serviceUrl").toString();
            String conversationId = conversation.get("id").toString();
            JSONObject from = (JSONObject) requestBody.get("from");
            JSONObject recepient = (JSONObject) requestBody.get("recipient");
            String url = serviceUrl+"v3/conversations/"+conversationId+"/activities/"+id;
            String userId = "";
            String aadObjectId = from.get("aadObjectId").toString();
            json.put("text", "Hai! How can I help you!!!");
            json.put("type", "message");
            json.put("from", recepient);
            json.put("conversation", conversation);
            json.put("recipient", from);
            json.put("replyToId", id);
            result = client.hitPOSTAPI(url, "POST", json);
            System.out.println(result);
            PrintWriter out = response.getWriter();
            out.print(result);
            out.flush();
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }
    }

TestRequest.java
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.commons.io.Charsets;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import com.google.common.io.CharStreams;
public class TestRequest {
    static String microsoft_AppID = "REPLACE YOUR APP_ID";
    static String microsoft_AppPwd = "REPLACE YOUR APP_PASSWORD";
    public static String hitPOSTAPI(String urlString, String methodType, JSONObject postParameter) {
        String result = "";
        try {
            HttpPost post = new HttpPost(urlString);
            StringEntity params = new StringEntity(postParameter.toString());
            System.err.println(postParameter.toString());
            post.addHeader("content-type", "application/json");
                post.addHeader("Authorization", "Bearer "+generateToken());
            post.setEntity(params);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(20 * 1000).setConnectionRequestTimeout(20*1000).setSocketTimeout(100*1000).build();
            HttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
            HttpResponse response = httpClient.execute(post);
            InputStream in = null;
            if (response.getStatusLine().getStatusCode()==200 &&response != null) {
                in = response.getEntity().getContent();
                result = CharStreams.toString(new InputStreamReader(
                        in, Charsets.UTF_8));
            }
            post.abort();
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        finally {
        }
        return result;
    }
    public static String generateToken() {
        String token = "";
        URL url = null;
        HttpURLConnection urlConnection = null;
        String result = "";
        try {
            url = new URL("https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token");
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setConnectTimeout(5000);
            urlConnection.setRequestProperty("Host", "login.microsoftonline.com");
            urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);
            urlConnection.setRequestMethod("POST");
            OutputStream wr = urlConnection.getOutputStream();
            String credentials = "grant_type=client_credentials&client_id="+microsoft_AppID+"&client_secret="+microsoft_AppPwd+"&scope=https://api.botframework.com/.default";
            wr.write(credentials.toString().getBytes());
            wr.flush();
            wr.close();
            if(urlConnection.getResponseCode()==200)
            {
                InputStream inputStream = urlConnection.getInputStream();
                InputStreamReader isReader = new InputStreamReader(inputStream);
                BufferedReader reader = new BufferedReader(isReader);
                StringBuffer sb = new StringBuffer();
                String str;
                while((str = reader.readLine())!= null){
                    sb.append(str);
                }
                JSONParser parser = new JSONParser();
                JSONObject obj = (JSONObject)parser.parse(sb.toString());
                token = obj.get("access_token").toString();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            urlConnection.disconnect();
        }
        return token;
    }
}

如果我做对了,由于可以有很多<script> import Button from './Button.svelte'; let text = 'Click me!'; let sayHello = () => alert('Hello!'); </script> <Button {text} {sayHello}/> <Button {text} {sayHello}/> <Button {text} {sayHello}/> ,最好省略以某种方式通过的道具

这是 Context API

<Button {text} {sayHello}/>

<script> import Button from './Button.svelte'; import { setContext } from 'svelte'; import { text, sayHello } from './data.js'; setContext(text, 'Click me!'); setContext(sayHello, () => alert('Hello!')); </script> <Button/> <Button/> <Button/> 中某处有./Button.svelte用法,依此类推


那么,是否能够省略类似道具传递的能力是使用Svelte的 Context API 的唯一原因吗?

1 个答案:

答案 0 :(得分:7)

那么,省略类似道具传递的能力是使用Svelte的Context API的唯一原因吗?

不,在我看来,这甚至不是上下文的很好用法。

这里的问题是,您混淆了父组件与其按钮子项之间的数据关系。

使用道具,可以明确按钮需要哪些数据以及数据来自何处。另一方面,使用上下文,您一次只能看到关系的一侧。在父级中,您看不到如何使用数据(甚至根本不使用数据)。在孩子中也是一样,您看不到它的来源。

例如,错误地涂上道具或移除仍然需要的道具,将导致即时可见的开发者警告(充分说明问题的确切位置)。有了上下文,您最终可能会得到一个不确定的值,该值会产生怪异的运行时行为,但难以追踪。

因此,当您在编码过程中并省去所有新鲜事物时,节省一点打字似乎是一个好主意,但这实际上增加了代码的复杂性,并且可能会给您带来麻烦。以后会给您带来很大的麻烦...如果您要我的意见,那不是一个很好的权衡。

在某些情况下,道具不是一种选择。也就是说,当数据使用者组件不是数据提供者组件的直接子代时。

例如,您的应用程序中可能会有某种用户会话。它很可能会存储在组件树根(例如App)的根附近的组件中,但在组件中需要更深层次的嵌套。例如,在显示用户名的组件中。或页面其他位置,根据用户是否通过身份验证显示一些部分。

您可以沿线路的每个组件通过道具,但这有点疯狂。这会将所有中间组件与它们绝对不关心的数据联系起来。

因此,在这种情况下,上下文是完全有意义的。您将在setContext组件中App,并且可以仅从需要它的组件中访问它。

另一个示例是某种“复合”组件,其中有一个包装组件(例如一个表单)和可以在其中使用的多个组件(例如输入),并且取决于组件中的某些设置。容器。

<Form>
  <Input />
</Form>

此处,Form组件无法将道具传递给Input组件,因为Input并不是直接在Form组件中创建的。它是通过一个插槽馈送给它的,Form无法看到此插槽的内容。

仍然,Input嵌套在结果组件树的Form下,因此您可以通过上下文在它们之间传递数据。

总而言之,上下文实际上是指您无法使用道具的情况。要么是因为它不切实际并导致体系结构不佳,要么是因为它在技术上是不可能的(插槽)。

作为上下文的替代方法,您可以将数据存储在提供者和使用者都将访问(例如import { setData, getData } from './data-source.js')的专用JS模块中,但这会使您的组件成为单例。此数据只能是全局的。另一方面,借助上下文,您可以根据需要拥有任意数量的隔离数据“作用域”,每个数据提供者组件实例一个。在上面的Form示例中,多个<Form>组件可以同时在您的应用程序中共存,每个组件在上下文中都有自己的数据。 (它们甚至可以嵌套在彼此内部,并且可以工作。)

最后,这里有一条建议。 Svelte中的上下文是使用JS Map对象实现的,因此您不必使用原始字符串作为上下文键。我通常使用从constants.js模块之类导出的普通对象(如果需要,也可以使用Symbol)。这在很大程度上缓解了我前面提到的模糊和IDE混淆问题。

constants.js

export const key = {name: 'my-context'}

Form.svelte

<script>
  import { setContext } from 'svelte'
  import { key } from './constants.js'

  setContext(key, { ... })
</script>

<slot />

Input.svelte

<script>
  import { getContext } from 'svelte'
  import { key } from './constants.js'

  const { ... } = getContext(key)
</script>

...

这消除了与原始字符串可能发生的上下文键冲突的任何风险。它将错误地快速转换为失败故障并发出严重的崩溃错误(这很好)。而且它为您的IDE提供了关于代码中发生的情况的更好的线索(开发人员可以轻松地将ES导入解析,而字符串只是它们的随机Blob),从而在您使用代码时为您提供更多帮助我需要重构...